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類型主要分成三種:

 

ManipulationStarted

該事件發生於當用戶將手指放置於螢幕上開始操作的時機點

ManipulationStartedEventArgs:提供ManipulationStarted的基本資料,例如:Touch下去的啟動座標。

 

ManipulationDelta:該事件發生於當用戶在螢幕上移動手指,並且它會重覆觸生

ManipulationDeltaEventArgs

負責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 (二篇都很重要)

Input for Windows Phone

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

Dotblogs Tags:

 

原贴:http://www.dotblogs.com.tw/pou/archive/2012/06/04/72592.aspx

你可能感兴趣的:(windows phone)