Windows Phone 7 - 淺談手勢(Gestures)運作
之前研究WP7時,總是針對應用層去研究,其實還有一塊是要去學習,也就是UI與UX。
然而,UI是要靠本身有點色系、排版等Sense的人,UX則是需要有點工業工程再加點程式設計在裡面的部分,
為什麼會這樣解釋呢?因為UX是用戶實際體驗所得到有經驗,那用戶要驗體的功能則是由程式撰寫而來的。
因此,最常見就是透過手勢的操作,讓整個UX的分數更高,那麼話就不多說,來看看WP7上怎麼做手勢的處理。
在WP7處理Gestures分成Silverlight與XNA二種方案,由於我比較熟悉寫應用程式,所以針對Silverlight進行說明。
〉Silverlight Framework – Manipulation Events:
在此Framework中允許開發人員處理手勢經由「manipulation events」。透過它來移動與取得影響範圍,進一步
回應Touch與Multi-Touch Input的事件。另外,UIElement、繼承UIElement的控件均支援手勢操作,包括:tap、double-tap、
hold、pan、flick…等,更方便開發人員使用。然而,Silverlight在處理manipulation events類型主要分成三種:
該事件發生於當用戶將手指放置於螢幕上開始操作的時機點。
‧ManipulationStartedEventArgs:提供ManipulationStarted的基本資料,例如:Touch下去的啟動座標。
‧ManipulationDelta:該事件發生於當用戶在螢幕上移動手指,並且它會重覆觸生。
負責ManipulationDelta事件觸發時的主要參數,其中屬性記錄了到目前為止移動的manipulation或
當前的manipulation等,協助處理時可以得知目前移動的狀態與類型,在這些屬性裡以「DeltaManipulation」
需特別注意,它內部包括很多transform物件。
‧ManipulationCompleted:該事件發生於當用戶將手指離開螢幕所觸發。
‧ManipulationCompletedEventArgs:提供ManipulationCompleted的事件資料,可取得最後影響的TotalManipulation。
其中有三個屬性要特別注意:
*FinalVelocities:取得操作的使用速度,它可用於協助判斷移動的量;
*IsInterial:用於識別發生ManipulationCompleted是否為一連貫的動作;
*TotalManipulation:取得當前操作的所有轉化總合;
這三個manipulation events是Windows Phone預設支援的機制,有關手勢的操作事件均以此為基礎。透過下方的範例簡單說明,
透過manipulation來完成一個手勢的功能,最後再補上其他手勢事件的處理機制。
[注意]
在該篇文章所舉用的範例,請透過實機測試才能呈現預期的效果。
範例1:透過ManipulationDelta事件,讓指定的物件隨著手指移動而跟著移動。
(a) 建立一個Rectangle,並且設定它的RenderTransform屬性;
1: <!-- 在XAML檔中,增加需要的Rectangle -->
2: <!--ContentPanel - place additional content here-->
3: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
4: <Canvas>
5: <Rectangle
6: Name="rectangle" Width="200" Height="200"
7: Fill="Blue" Stroke="Blue" StrokeThickness="1"
8: ManipulationDelta="rectangle_ManipulationDelta" />
9: </Canvas>
10: </Grid>
(b) 為Rectangle註冊ManipulationDelta事件,透過ManipluationDelta來移動它的位置;
1: public MainPage()
2: {
3: InitializeComponent();
4: //初始化TransformGroup
5: Init_Transform();
6: }
7:
8: //Transform需要的變數
9: private TransformGroup transformGroup;
10: private TranslateTransform translation;
11:
12: private void Init_Transform()
13: {
14: this.transformGroup = new TransformGroup();
15: this.translation = new TranslateTransform();
16:
17: //建立一個新的TransformGroup,並且設定該Group要呈現的影響項目:位置
18: this.transformGroup.Children.Add(this.translation);
19: //將TransformGroup指定給Rectangle物件
20: this.rectangle.RenderTransform = this.transformGroup;
21: }
22:
23: private void rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
24: {
25: //透過手指移動的x與y,指定給定義好的Translatefofrm變數,進而影響Rectangle物件
26: this.translation.X += e.DeltaManipulation.Translation.X;
27: this.translation.Y += e.DeltaManipulation.Translation.Y;
28: }
以上是簡單的範例,在<How to: Handle Manipulation Events>該篇裡有提到幾個類別是需要注意的,以下簡單說明:
‧TransformGroup:代表一個由多個transform物件組合而成的物件,它的Children屬性用於描述該Group該有的樣子;
‧TranslateTransform:代表一個移動(move)的轉換物件,具有二個維度:x與y座標,呈現於物件移動的位置,使用一指操作;
‧ScaleTransform:代表一個尺度(scale)的轉換物件,具有二個維度:x與y座標,呈現於物件改變的尺度,使用二指操作;
〉Silverlight Framework - GestureListener:
接著介紹在Silverlight for Windows Phone Toolkit中的一個元件:GestureListener ,該元件具有豐富的手勢處理功能與使用者經驗。
如果未安裝Toolkit的話,可以先下載並安裝它;其GestureListener 已增加了數個蠻好用的Event Handler來處理手勢的事件,如下:
[範例事前準備]
1. 安裝Silverlight for Windows Phone Toolkit;
2. 於MainPage.xaml中,新增一個Recentagle物件,並且加上GestureLisener元件,如下:
1: <!--ContentPanel - place additional content here-->
2: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
3: <Canvas>
4: <!-- 新增一個Rectangle物件,並指定GestureListener處理事件-->
5: <Rectangle x:Name="rectangle" Width="200" Height="200"
6: Fill="Blue" Stroke="Blue" StrokeThickness="5">
7: <my:GestureService.GestureListener>
8: <my:GestureListener
9: Tap="GestureListener_Tap"
10: Hold="GestureListener_Hold"
11: Flick="GestureListener_Flick"
12: DoubleTap="GestureListener_DoubleTap"
13: GestureBegin="GestureListener_GestureBegin"
14: GestureCompleted="GestureListener_GestureCompleted"
15: DragDelta="GestureListener_DragDelta"
16: DragStarted="GestureListener_DragStarted"
17: DragCompleted="GestureListener_DragCompleted"
18: PinchStarted="GestureListener_PinchStarted"
19: PinchDelta="GestureListener_PinchDelta"
20: PinchCompleted="GestureListener_PinchCompleted">
21: </my:GestureListener>
22: </my:GestureService.GestureListener>
23: <Rectangle.RenderTransform>
24: <TranslateTransform x:Name="translation" />
25: </Rectangle.RenderTransform>
26: </Rectangle>
27: </Canvas>
28: </Grid>
A. Tap (搭配GestureEventArgs):
事件發生用手指觸控(輕敲)UIElement與離開UIElement。
[範例]
1: private void GestureListener_Tap(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
2: {
3: //識別觸發Tap的來源者是否為rectangle物件
4: if (e.OriginalSource == rectangle)
5: {
6: //每Tap一點就換色
7: Random tRand = new Random();
8: rectangle.Fill = new SolidColorBrush(
9: Color.FromArgb(255, (byte)tRand.Next(256),
10: (byte)tRand.Next(256),
11: (byte)tRand.Next(256)));
12: }
13: }
B. DoubleTap (搭配GestureEventArgs):
事件發生連續快速二次Tap(輕敲)動作於UIElement。
[範例]
1: private void GestureListener_DoubleTap(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
2: {
3: //在DoubleTap後,移動現在Rectangle回到指定的座標。
4: translation.X = translation.Y = 10;
5: }
C. Hold (搭配GestureEventArgs):
事件發生手指接觸UIElement,並持續停留在同一個位置一段時間。
[範例]
1: private void GestureListener_Hold(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
2: {
3: //壓著rectangle一段時間,改變顏色與彈出訊息
4: if (e.OriginalSource == rectangle)
5: rectangle.Fill = new SolidColorBrush(
6: Color.FromArgb(255, 225, 255, 255));
7: MessageBox.Show("You are holding the rectangle!", "Hold", MessageBoxButton.OK);
8: }
D. Flick (搭配FlickGestureEventArgs):
事件發生手指在螢幕上接觸UIElement,並且進行拖動,移動UIElement超過現有的螢幕,且沒有結束,即啟動該事件。
[範例]
1: private void GestureListener_Flick(object sender, FlickGestureEventArgs e)
2: {
3: if (e.Direction == System.Windows.Controls.Orientation.Horizontal)
4: {
5: //利用FlickGestureEventArgs的Angle(甩尾的角度)來識別
6: if (e.Angle > 270 || e.Angle < 90)
7: ChangeFlickTip(true);
8: else
9: ChangeFlickTip(false);
10: }
11: }
12:
13: private int gCurrentIdx = 1;
14: private void ChangeFlickTip(bool pType)
15: {
16: if (pType == true)
17: {
18: //往下一個
19: gCurrentIdx += 1;
20: }
21: else
22: {
23: //往上一個
24: gCurrentIdx -= 1;
25: }
26: Dispatcher.BeginInvoke(() =>
27: {
28: MessageBox.Show(string.Format("Current Idx: {0}", gCurrentIdx));
29: });
30: }
此範例可參考<Building Touch Interfaces for Windows Phones, Part 4>與<Windows Phone 7 Gestures>有更容易理解的範例。
E. GestureBegin、GestureCompleted (搭配GestureEventArgs):
所有手勢事件觸發的啟始點與結束點,不論是Tap、DoubleTap、Flick或Hold等,均會由GestureBegin開始,GestureCompleted結束。
[範例]
1: #region GestureBegin與GestureCompleted
2: private void GestureListener_GestureBegin(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
3: {
4: //取得Gesture的啟始點
5: var tPosition = e.GetPosition(rectangle);
6: }
7:
8: private void GestureListener_GestureCompleted(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
9: {
10: //取得Gesture的結束點
11: var tPosition = e.GetPosition(rectangle);
12: }
13: #endregion
F. DragStarted (搭配DragStartedGestureEventArgs)、DragDelta (搭配DragDeltaGestureEventArgs)、
DragCompleted (搭配DragCompletedGestureEventArgs):
事件發生於當手指點壓著UIElement(DragStarted),接著進行拖曳一段距離(DragDelta)後,放開手指壓著的UIEelemnt(DragCompleted)。
[範例]
1: #region Drag系列
2: private void GestureListener_DragStarted(object sender, DragStartedGestureEventArgs e)
3: {
4: //取得移動方向
5: Orientation Orientation = e.Direction;
6: }
7:
8: private void GestureListener_DragDelta(object sender, DragDeltaGestureEventArgs e)
9: {
10: //隨著拖曳的垂直/水平變動量,移動x與y的值
11: this.translation.X += e.HorizontalChange;
12: this.translation.Y += e.VerticalChange;
13: }
14:
15: private void GestureListener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
16: {
17: Orientation Orientation = e.Direction;
18: double tHorChange = e.HorizontalChange;
19: double tVerChange = e.VerticalChange;
20: }
21: #endregion
G. PinchStarted(搭配PinchStartedGestureEventArgs)、PinchDelta(搭配PinchGestureEventArgs)、
PinchCompleted(搭配PinchGestureEventArgs):
事件發生於二個手指點壓著UIElement(PinchStarted),接著二指拉開拉近的一段距離(PinchDelta)後,放開手指壓著的UIEelemnt(PinchCompleted)。
[範例]
1: #region Pinch系列
2: private void GestureListener_PinchStarted(object sender, PinchStartedGestureEventArgs e)
3: {
4: //取得二個手指之間的距離
5: double tDistance = e.Distance;
6: //取得經由二個手指定義的Angle角度
7: double tAngle = e.Angle;
8: }
9:
10: private void GestureListener_PinchDelta(object sender, PinchGestureEventArgs e)
11: {
12: //透過二指的縮放,調整rectanlge的規模
13: scale.ScaleX = e.DistanceRatio;
14: scale.ScaleY = e.DistanceRatio;
15: }
16:
17: private void GestureListener_PinchCompleted(object sender, PinchGestureEventArgs e)
18: {
19: //二個手指放開後,又自動復原
20: scale.ScaleX = scale.ScaleY = 1;
21: scale.CenterX = scale.CenterY = 0;
22: }
23: #endregion
[範例程式]
======
[補充]
〉Gestures Support in the XNA Framework:
XNA在Gestures的支援是最完整的,並提供更多元的處理機制,以補捉到所有的Gestures事件。
擷錄<Gesture Support in the XNA Framework>的內容,如下表:
Gesture Type | Description |
Tap | 用手指觸控(輕敲)螢幕與離開螢幕。 |
DoubleTap | 該類型代表連續二個Tap手勢。 |
Hold | 手指接觸螢幕,並持續停留在同一個位置一段時間。 |
FreeDrag | 手指觸控螢幕,並往任何方向移動。 |
VerticalDrag | 手指觸控螢幕,並由上往下或由下往下移動。 |
HorizontalDrag | 手指觸控螢幕,並由左往右或由右往左移動。 |
DragComplete | 當FreeDrag、VerticalDrag、HorizontalDrag移動結束後所觸發。 |
Flick | 手指在螢幕上拖動,移動至不同的螢幕,並且沒有結束。 |
Pinch | 運用二個手指按在螢幕上移動。 |
PinchComplete | Pinch手勢動作完成後,觸發的事件。 |
〉FlickGestureEventArgs重點屬性:
Name | Description |
Angle | Flick轉換的角度。 |
Direction | Flick手勢的方向,協助確定Flick的速度。 |
Handled | 如果該屬性被設定為true,它將不會繼續往下一個事件傳送,取消bubbling的流程。 |
HorizontalVelocity | Flick的水平轉換速度。 |
OriginalSource | Flick觸發的來源者,透過Z-Order的方式找到正確的Touch對象。 |
VerticalVelocity | Flick的垂直轉換速度。 |
TouchPosition | 屬於Protected的屬性,用於記錄接觸點的資訊。 |
======
以上是介紹在WP7處理手勢操作的概念與範例,其實手勢操作的體驗,為第二個最直接的讓用戶覺得有意思的地方,
因此,對於資料的分頁,轉場的效果,通常都會透過手勢來加以定義。
References:
‧Gesture Support for Windows Phone & Windows Phone 7 Gestures
‧Touch gestures on Windows Phone 7 (必讀)
‧Windows Phone 7 Gestures Cheat Sheet (原理)
‧Handling Input on Windows Phone 7 : Touch Input (part 3) - Multi-Point Touch
‧Drawing in WP7: #2 Drawing shapes with finger & Understanding Windows Phone 7 Gestures
‧Input in Silverlight for Windows Phone & How to: Handle Manipulation Events (二篇都很重要)
‧Designing for Gestures on Windows Phone 7 (教學)
‧Developing Applications for Windows Phone 7 : Designing with Blend
‧Multi-Touch Manipulation Events in WPF (WPF針對Tocuh事件的原理) & Windows Phone 上的触控手势
‧Windows Phone 7 Silverlight Programming - MultiTouch and Manipulation (重要)
‧How to: Specify On-Screen Keyboard Layout for a TextBox
‧Building Touch Interfaces for Windows Phones, Part 4 (必讀)
=== XNA參考文獻 ===
‧Working with Touch Input (Windows Phone)
‧Detecting Gestures on a Multi-touch Screen (Windows Phone)
‧Windows Phone 7 Gestures Compared