與眾不同 windows phone (25) - Input(輸入)之捕獲 UIElement 之外的觸控操作, Silverlight 方式捕獲手勢操作, XNA 方式捕獲手勢操作, 多點觸控
作者:webabcd
介紹
與眾不同 windows phone 7.5 (sdk 7.1) 之輸入
- 捕獲 UIElement 之外的觸控操作
- Silverlight 方式捕獲手勢操作
- XNA 方式捕獲手勢操作
- 多點觸控
示例
1、演示如何捕獲 UIElement 之外的觸控操作
OutsideCapture.xaml
<phone:PhoneApplicationPage x:Class="Demo.Input.Touch.OutsideCapture" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <Grid x:Name="LayoutRoot" Background="Transparent"> <Rectangle Name="rect" Width="100" Height="100" Fill="Red" MouseLeftButtonDown="rect_MouseLeftButtonDown" MouseLeftButtonUp="rect_MouseLeftButtonUp" MouseMove="rect_MouseMove" /> <TextBlock Name="lblMsg" VerticalAlignment="Top" TextWrapping="Wrap" Text="用手指觸摸紅色方塊,然后將手指移除紅色方塊區域" /> </Grid> </phone:PhoneApplicationPage>
OutsideCapture.xaml.cs
/* * 演示如何在 UIElement 外響應 UIElement 上的觸控事件 * * UIElement - UI 元素 * CaptureMouse() - 捕獲外部觸摸事件,這樣即使觸摸事件在 UIElement 之外也可以響應 * ReleaseMouseCapture() - 取消外部觸摸事件的捕獲 * * 注: * 調用 UIElement 的 CaptureMouse() 方法需要滿足以下條件 * 1、當前沒有任何 UIElement 正在捕獲中 * 2、必須在 UIElement 的 MouseLeftButtonDown 事件中調用 CaptureMouse() 方法 */ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; namespace Demo.Input.Touch { public partial class OutsideCapture : PhoneApplicationPage { public OutsideCapture() { InitializeComponent(); } private void rect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { rect.CaptureMouse(); lblMsg.Text = "觸摸點坐標為:" + e.GetPosition(LayoutRoot).ToString(); } private void rect_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { rect.ReleaseMouseCapture(); } private void rect_MouseMove(object sender, MouseEventArgs e) { // 調用了 rect.CaptureMouse() 之后,即使觸控移出 rect 也可以響應觸控事件 lblMsg.Text = "觸摸點坐標為:" + e.GetPosition(LayoutRoot).ToString(); } } }
2、演示如何通過 Silverlight 捕獲手勢操作
ManipulationDemo.xaml
<phone:PhoneApplicationPage x:Class="Demo.Input.Touch.ManipulationDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <Grid x:Name="LayoutRoot" Background="Transparent"> <StackPanel Orientation="Vertical"> <TextBlock Text="請隨便做一些手勢操作,以查看演示效果" /> <TextBlock Name="lblMsg" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
ManipulationDemo.xaml.cs
/* * 演示如何在 Silverlight 下捕獲手勢操作 * * UIElement - UI 元素 * ManipulationStarted - 手勢操作開始時觸發的事件,即觸摸屏幕時觸發的事件(事件參數:ManipulationStartedEventArgs) * ManipulationDelta - 手勢操作過程中觸發的事件(事件參數:ManipulationDeltaEventArgs) * ManipulationCompleted - 手持操作完成時觸發的事件(事件參數:ManipulationCompletedEventArgs) * * * ManipulationStartedEventArgs * ManipulationContainer - 手勢操作的容器,即坐標的參照物 * ManipulationOrigin - 手勢起始點坐標 * Complete() - 停止捕獲手勢操作,即不會再觸發 ManipulationDelta 事件 * * ManipulationDeltaEventArgs * ManipulationContainer - 手勢操作的容器,即坐標的參照物 * ManipulationOrigin - 當前手勢的中心點坐標 * Complete() - 停止捕獲手勢操作,即不會再觸發 ManipulationDelta 事件 * DeltaManipulation.Scale - 最近一次縮放比的變化 * DeltaManipulation.Translation - 最近一次位移的變化 * CumulativeManipulation.Scale - 縮放比的累計的變化 * CumulativeManipulation.Translation - 位移的累計的變化 * * ManipulationCompletedEventArgs * ManipulationContainer - 手勢操作的容器,即坐標的參照物 * ManipulationOrigin - 當前手勢的中心點坐標 * TotalManipulation.Scale - 縮放比的總計變化 * TotalManipulation.Translation - 位移的總計變化 * IsInertial - 手勢操作收尾時是否有慣性 * FinalVelocities.LinearVelocity - 如果手勢操作收尾時有慣性,則此屬性會返回其線性速度 */ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; namespace Demo.Input.Touch { public partial class ManipulationDemo : PhoneApplicationPage { public ManipulationDemo() { InitializeComponent(); // 注冊相關手勢事件 LayoutRoot.ManipulationStarted += new EventHandler<ManipulationStartedEventArgs>(LayoutRoot_ManipulationStarted); LayoutRoot.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(LayoutRoot_ManipulationDelta); LayoutRoot.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(LayoutRoot_ManipulationCompleted); } void LayoutRoot_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { lblMsg.Text = string.Format("手勢起始點坐標 - x: {0},y: {1}", e.ManipulationOrigin.X, e.ManipulationOrigin.Y); } void LayoutRoot_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) { lblMsg.Text = string.Format("當前手勢的中心點坐標 - x: {0},y: {1}", e.ManipulationOrigin.X, e.ManipulationOrigin.Y); lblMsg.Text += Environment.NewLine; lblMsg.Text += "縮放比最近的變化:" + e.DeltaManipulation.Scale.ToString(); lblMsg.Text += Environment.NewLine; lblMsg.Text += "位移最近的變化" + e.DeltaManipulation.Translation.ToString(); lblMsg.Text += Environment.NewLine; lblMsg.Text += "縮放比總共的變化:" + e.CumulativeManipulation.Scale.ToString(); lblMsg.Text += Environment.NewLine; lblMsg.Text += "位移總共的變化:" + e.CumulativeManipulation.Translation.ToString(); lblMsg.Text += Environment.NewLine; } void LayoutRoot_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { lblMsg.Text = string.Format("當前手勢的中心點坐標 - x: {0},y: {1}", e.ManipulationOrigin.X, e.ManipulationOrigin.Y); lblMsg.Text += Environment.NewLine; lblMsg.Text += "縮放比總共的變化:" + e.TotalManipulation.Scale.ToString(); lblMsg.Text += Environment.NewLine; lblMsg.Text += "位移總共的變化:" + e.TotalManipulation.Translation.ToString(); lblMsg.Text += Environment.NewLine; lblMsg.Text += "手勢操作收尾時是否有慣性:" + e.IsInertial.ToString(); lblMsg.Text += Environment.NewLine; lblMsg.Text += "如果手勢操作收尾時有慣性,其速度為:" + e.FinalVelocities.LinearVelocity.ToString(); } } }
3、演示如何通過 XNA 捕獲手勢操作
XNAGesture.xaml
<phone:PhoneApplicationPage x:Class="Demo.Input.Touch.XNAGesture" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <Grid x:Name="LayoutRoot" Background="Transparent"> <StackPanel Orientation="Vertical"> <TextBlock Text="請隨便做一些手勢操作,以查看演示效果" /> <TextBlock Name="lblMsg" TextWrapping="Wrap" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
XNAGesture.xaml.cs
/* * 演示如何在 XNA 下捕獲手勢操作 * * TouchPanel - 觸摸面板 * DisplayOrientation - 顯示方向(Microsoft.Xna.Framework.DisplayOrientation 枚舉) * Default, LandscapeLeft, LandscapeRight, Portrait * DisplayWidth - 寬 * DisplayHeight - 高 * IsGestureAvailable - 當前是否存在有效的手勢操作 * EnabledGestures - 指定需要捕獲的手勢操作類型(Microsoft.Xna.Framework.Input.Touch.GestureType 枚舉) * None, Tap, DoubleTap, Hold, HorizontalDrag, VerticalDrag, FreeDrag, Pinch, Flick, DragComplete, PinchComplete * GetCapabilities() - 返回 TouchPanelCapabilities 類型對象 * ReadGesture() - 返回 GestureSample 類型對象 * * * TouchPanelCapabilities - 觸摸板的能力 * IsConnected - 觸摸板是否有效 * MaximumTouchCount - 觸摸板可以同時捕獲的最大點數,即最大支持幾點觸摸 * * GestureSample - 手勢信息 * GestureType - 手勢操作類型 * Position - 兩點手勢操作時,第一點的位置 * Position2 - 兩點手勢操作時,第二點的位置 * Delta - 兩點手勢操作時,第一點的位移的最近變化值 * Delta2 - 兩點手勢操作時,第二點的位移的最近變化值 * Timestamp - 此手勢開始的時間戳(此值為系統自上次啟動以來到此手勢開始時所經過的時間) */ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using Microsoft.Xna.Framework.Input.Touch; namespace Demo.Input.Touch { public partial class XNAGesture : PhoneApplicationPage { public XNAGesture() { InitializeComponent(); // 在手勢操作完成后獲取相關的手勢信息 LayoutRoot.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(LayoutRoot_ManipulationCompleted); TouchPanelCapabilities tpc = TouchPanel.GetCapabilities(); lblMsg.Text = "觸摸板是否有效:" + tpc.IsConnected; lblMsg.Text += Environment.NewLine; lblMsg.Text += "觸摸板最大支持 " + tpc.MaximumTouchCount + " 點觸摸"; lblMsg.Text += Environment.NewLine; // 指定需要捕獲的手勢類型(只有指定的類型才能捕獲到) TouchPanel.EnabledGestures = GestureType.Tap | GestureType.DoubleTap | GestureType.Hold | GestureType.HorizontalDrag | GestureType.VerticalDrag | GestureType.FreeDrag | GestureType.Pinch | GestureType.Flick | GestureType.DragComplete | GestureType.PinchComplete; } // 當一次手勢操作完成后,獲取此次手勢操作包含的全部手勢信息 void LayoutRoot_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { /* * 由於一次手勢操作可能會有多個手勢信息,所以這里要一直輸出手勢信息直至沒有有效的手勢為止 * 這里的一次手勢操作指的是手指按下到抬起后,這期間可能會有多個手勢信息(比如一次手勢操作可能會由多個水平移動、多個垂直移動等組成) * 可以在每一幀當 TouchPanel.IsGestureAvailable 有效時都獲取一下 TouchPanel.ReadGesture(),這樣就可以即時獲取到當前手勢信息 */ while (TouchPanel.IsGestureAvailable) { GestureSample gs = TouchPanel.ReadGesture(); lblMsg.Text += gs.GestureType.ToString() + ","; } } } }
4、演示如何響應多點觸控
MutiTouch.xaml
<phone:PhoneApplicationPage x:Class="Demo.Input.Touch.MutiTouch" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <Grid x:Name="LayoutRoot" Background="Transparent"> <StackPanel Orientation="Vertical"> <TextBlock Text="請多點觸摸此屏幕,以查看演示效果" /> <TextBlock Name="lblMsg" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
MutiTouch.xaml.cs
/* * 演示系統對多點觸摸的支持 * * * TouchPanel - 觸摸面板 * GetState() - 返回觸摸面板上,被觸摸的所有點的狀態(TouchCollection 類型) * * TouchCollection - 觸摸點的集合(TouchLocation 的集合) * * TouchLocation - 觸摸點 * Position - 觸摸點的坐標 * State - 觸摸點的狀態(TouchLocationState 類型) * * TouchLocationState - 觸摸點狀態(Microsoft.Xna.Framework.Input.Touch.TouchLocationState 枚舉) * Invalid - 無效 * Released - 被釋放 * Pressed - 被觸摸,即一個新的觸摸點 * Moved - 被觸摸后移動 * * * 注:目前只支持 4 點觸摸 */ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using System.Windows.Navigation; using Microsoft.Xna.Framework.Input.Touch; namespace Demo.Input.Touch { public partial class MutiTouch : PhoneApplicationPage { public MutiTouch() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering); } void CompositionTarget_Rendering(object sender, EventArgs e) { this.Dispatcher.BeginInvoke(delegate { lblMsg.Text = ""; }); // 獲取當前觸摸點集合 TouchCollection touchLocations = TouchPanel.GetState(); for (int i = 0; i < touchLocations.Count; i++) { TouchLocation touchLocation = touchLocations[i]; float x = touchLocation.Position.X; float y = touchLocation.Position.Y; // 顯示每個觸摸點的坐標及狀態 this.Dispatcher.BeginInvoke(new InvokeUIWidthParameterDelegate(ShowMessage), i, x, y, touchLocation.State); } } void ShowMessage(int i, float x, float y, TouchLocationState state) { lblMsg.Text += string.Format("觸摸點{0}坐標 - X: {1},Y: {2},狀態: {3}", i, x, y, state.ToString()); lblMsg.Text += Environment.NewLine; } private delegate void InvokeUIWidthParameterDelegate(int i, float x, float y, TouchLocationState state); } }
OK
[源碼下載]
