Windows phone 8 的應用 與一般的Pc應用在輸入方式上最大的不同就是:Windows phone 8主要依靠觸控操作。因此在輸入方式上引入一套全新的觸控操作方式,我們需要重新定義相關的事件和方法。觸控覆蓋了Windows phone 8絕大部分用戶的輸入,如何處理輸入呢,微軟從SL和XNA兩個方面提供了多種選擇,並支持多點觸控,下面我們看看具體的實現方式。
一、觸控輸入的處理方式
Silverlight
1)操作事件
用於觸控操作是一個過程性的,因此通過三個事件ManipulationStarted、ManipulationDelta、ManipulationCompleted來控制觸控的整個過程。他們分別為:
ManipulationStarted: 分別標識了觸控開始時發生
ManipulationDelta: 觸控過程中位置變更時發生
ManipulationCompleted: 觸控結束時發生
XNA
2)讀取手勢
手勢是將觸控輸入數據解釋為一組常用動作(如點按、輕拂和捏合)的高級方式。XNA中為我們封裝了一些常用的基本手勢操作,下表描述了 Windows Phone 中的一些常用筆勢。
點按 手指觸摸屏幕,然后釋放。
連按 手指點按屏幕兩次,然后松開。
長按 手指觸摸屏幕,並保持短暫停留。
拖動 手指觸摸屏幕,並向任何方向移動。
輕拂 手指在屏幕上滑動,且不停止即抬起。
捏合 兩個手指在屏幕上點按,並移動。
二、熟悉操作事件
在各個事件中,我們可以獲取不同的坐標偏移位置信息以及縮放大小信息,這樣我們可以通過編程方便的控制,由於API提供的各類偏移縮放名稱太多,為了方便理解,首先,我們通過圖解說明相關的名稱概念。見下圖,我們實現了一個應用,功能是把一個矩形控件通過觸碰操作從虛線所示位置平移到另一位置,黃色軌跡代表拖動的路線:

然后我們看看三個事件,各個事件中分別可以獲取一些什么信息,首先,我們要定義一個矩形,然后定義他的CompositeTransform位置縮放轉換。另外我們要定義一個顏色刷,當觸控操作開始時改變矩形的顏色,結束時恢復顏色。我們需要一些准備信息,然后我們需要在構造方法中初始化作用於矩形的三個觸控事件。新建工程,添加如下代碼:
[XAML] <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Canvas Margin="0,-58,0,58">
<Rectangle
x:Name="rectangle"
Width="200" Height="200"
Fill="Blue" Stroke="Blue" StrokeThickness="0" RenderTransformOrigin="0.5,0.5" Canvas.Top="37" >
</Rectangle>
</Canvas>
</Grid>
[C#]
public partial class MainPage : PhoneApplicationPage
{
private CompositeTransform compositeTransform = new CompositeTransform();
private Brush startBgColor;
private Brush bgColor = new SolidColorBrush(Colors.Orange);
//觸碰初始被觸碰控件本身平移量
double startX;
double startY;
//初次觸碰點相對於被拖動控件基准點的坐標
double firstTranslateX;
double firstTranslateY;
public MainPage()
{
InitializeComponent();
rectangle.RenderTransform = compositeTransform;
//觸控開始時發生
rectangle.ManipulationStarted += new EventHandler<ManipulationStartedEventArgs>(Rectangle_ManipulationStarted);
//觸控過程中位置變更時發生
rectangle.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(Rectangle_ManipulationDelta);
//觸控結束時發生
rectangle.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(Rectangle_ManipulationCompleted);
}
private string ConvertString(double value)
{
return (Math.Round(value * 100) / 100).ToString();
}
private string ConvertString(Point value)
{
return "{" + (Math.Round(value.X * 100) / 100).ToString() + "," + (Math.Round(value.Y * 100) / 100).ToString() + "}";
}
}
1) ManipulationStarted
[C#] void Rectangle_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
startBgColor = rectangle.Fill;
(e.ManipulationContainer as Rectangle).Fill = bgColor;
//這兩個值效果一樣,都是指被觸控控件本身
//(e.OriginalSource as Rectangle).Fill = endBgColor;
//觸碰初始被觸碰控件本身平移量
startX = compositeTransform.TranslateX;
startY = compositeTransform.TranslateY;
//初次觸碰點相對於被拖動控件基准點的坐標
firstTranslateX = e.ManipulationOrigin.X;
firstTranslateY = e.ManipulationOrigin.Y;
}
2) ManipulationDelta
[C#] void Rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
//當前觸碰點相對於被觸控控件基准點的坐標
ox.Text = ConvertString(e.ManipulationOrigin.X);
oy.Text = ConvertString(e.ManipulationOrigin.Y);
//當前觸碰點相對於上一觸碰點的坐標偏移
dx.Text = ConvertString(e.DeltaManipulation.Translation.X);
dy.Text = ConvertString(e.DeltaManipulation.Translation.Y);
//當前觸碰點相對於初次觸碰點的坐標偏移
tx.Text = ConvertString(e.CumulativeManipulation.Translation.X);
ty.Text = ConvertString(e.CumulativeManipulation.Translation.Y);
//控件跟隨移動
//compositeTransform.TranslateX += e.DeltaManipulation.Translation.X;
//compositeTransform.TranslateY += e.DeltaManipulation.Translation.Y;
//實時精准定位移動,不考慮連貫性
compositeTransform.TranslateX += e.DeltaManipulation.Translation.X + e.ManipulationOrigin.X - firstTranslateX;
compositeTransform.TranslateY += e.DeltaManipulation.Translation.Y + e.ManipulationOrigin.Y - firstTranslateY;
//相對於上次的縮放量
//if (e.DeltaManipulation.Scale.X > 0 && e.DeltaManipulation.Scale.Y > 0)
//{
// compositeTransform.ScaleX *= e.DeltaManipulation.Scale.X;
// compositeTransform.ScaleY *= e.DeltaManipulation.Scale.Y;
//}
if (e.PinchManipulation != null)
{
//初次主次觸控點相對於被觸控控件基准點的坐標
pa.Text = ConvertString(e.PinchManipulation.Original.PrimaryContact)
+ " " + ConvertString(e.PinchManipulation.Original.SecondaryContact)
+ " " + ConvertString(e.PinchManipulation.Original.Center);
//當前主次觸控點相對於被觸控控件基准點的坐標
pb.Text = ConvertString(e.PinchManipulation.Current.PrimaryContact)
+ " " + ConvertString(e.PinchManipulation.Current.SecondaryContact)
+ " " + ConvertString(e.PinchManipulation.Current.Center);
//當前主次觸控點間距÷初次主次觸碰點間距
pc.Text = ConvertString(e.PinchManipulation.CumulativeScale);
//當前主次觸控點間距÷上一主次觸碰點間距
pd.Text = ConvertString(e.PinchManipulation.DeltaScale);
}
}
3) ManipulationCompleted
[C#] void Rectangle_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
rectangle.Fill = startBgColor;
}
三、通過TouchPanel獲取基本的手勢以及其他信息
在XNA中,我們可以通過TouchPanel獲取基本手勢信息,手勢必須被啟用才能夠識別。因此我們要在構造函數中定義要啟用的手勢。
[C#] public MainPage()
{
InitializeComponent();
rectangle.RenderTransform = compositeTransform;
//設置可識別的手勢,必須設置才能被啟用
TouchPanel.EnabledGestures = GestureType.Hold | GestureType.Tap | GestureType.DoubleTap | GestureType.Flick | GestureType.Pinch;
}
這個時候,我們可以在觸控結束時,判斷當前觸控的手勢類型,另外,在觸控進行的過程中,我們可以實時獲取當前每個觸控點的相關狀態信息,我們還可以通過TouchPanel識別當前設備對觸控的支持性。
[C#] protected override void OnNavigatedTo(NavigationEventArgs e)
{
//獲取設備對觸控的支持性
var a = TouchPanel.GetCapabilities();
//當前設備是否支持觸控
if (a.IsConnected)
{
//當前設備支持幾個觸控點
CapabilitiesText.Text = "當前設備支持[ "+a.MaximumTouchCount+" ]點觸控";
}
base.OnNavigatedTo(e);
}
void Rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
//全部觸控點的絕對坐標和狀態
TouchCollection touchCollection = TouchPanel.GetState();
string stateString = string.Empty;
foreach (var item in touchCollection)
{
stateString += " " + item.Position.ToString() + "[" + item.State.ToString() + "]";
}
TouchCollectionText.Text = stateString;
}
void Rectangle_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
rectangle.Fill = startBgColor;
//當手勢可用時執行
while (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
//獲取當前的識別的手勢類型
p.Text = gesture.GestureType.ToString();
}
}
四、完整編碼
[XAML]<phone:PhoneApplicationPage
x:Class="PhoneApp1.MainPage"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot 是包含所有頁面內容的根網格-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel 包含應用程序的名稱和頁標題-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0">
<Run Text="觸控"/>
<Run Text="輸入"/>
</TextBlock>
</StackPanel>
<!--ContentPanel - 在此處放置其他內容-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Canvas Margin="0,-58,0,58">
<Rectangle
x:Name="rectangle"
Width="200" Height="200"
Fill="Blue" Stroke="Blue" StrokeThickness="0" RenderTransformOrigin="0.5,0.5" Canvas.Top="37" >
</Rectangle>
</Canvas>
</Grid>
<TextBlock x:Name="CapabilitiesText" FontSize="16" Foreground="YellowGreen" HorizontalAlignment="Left" Margin="10,205,0,0" Grid.Row="1" TextWrapping="Wrap" Text="當前設備不支持觸控" VerticalAlignment="Top"/>
<TextBlock Foreground="Red" HorizontalAlignment="Left" Margin="274,205,0,0" Grid.Row="1" TextWrapping="Wrap" Text="手勢:" VerticalAlignment="Top"/>
<TextBlock Text="None" x:Name="p" Foreground="Red" HorizontalAlignment="Left" Margin="323,205,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock Text="無觸控點" x:Name="TouchCollectionText" Foreground="Coral" HorizontalAlignment="Left" Margin="10,255,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock FontSize="16" Text="全部觸控點的絕對坐標和狀態" Foreground="Coral" HorizontalAlignment="Left" Margin="10,235,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock Foreground="White" HorizontalAlignment="Left" Margin="10,343,0,0" Grid.Row="1" TextWrapping="Wrap" Text="X:" VerticalAlignment="Top"/>
<TextBlock FontSize="16" Foreground="White" HorizontalAlignment="Left" Margin="10,323,0,0" Grid.Row="1" TextWrapping="Wrap" Text="當前觸碰點相對於被觸控控件基准點的坐標:" VerticalAlignment="Top"/>
<TextBlock Foreground="White" HorizontalAlignment="Left" Margin="97,343,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Y:" VerticalAlignment="Top"/>
<TextBlock Text="0" x:Name="ox" Foreground="White" HorizontalAlignment="Left" Margin="29,343,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock Text="0" x:Name="oy" Foreground="White" HorizontalAlignment="Left" Margin="115,343,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock Foreground="Yellow" HorizontalAlignment="Left" Margin="10,393,0,0" Grid.Row="1" TextWrapping="Wrap" Text="X:" VerticalAlignment="Top"/>
<TextBlock FontSize="16" Foreground="Yellow" HorizontalAlignment="Left" Margin="10,374,0,0" Grid.Row="1" TextWrapping="Wrap" Text="當前觸碰點相對於上一觸碰點的坐標偏移:" VerticalAlignment="Top"/>
<TextBlock Foreground="Yellow" HorizontalAlignment="Left" Margin="97,393,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Y:" VerticalAlignment="Top"/>
<TextBlock Text="0" x:Name="dx" Foreground="Yellow" HorizontalAlignment="Left" Margin="29,393,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock Text="0" x:Name="dy" Foreground="Yellow" HorizontalAlignment="Left" Margin="115,393,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock Foreground="Red" HorizontalAlignment="Left" Margin="10,440,0,0" Grid.Row="1" TextWrapping="Wrap" Text="X:" VerticalAlignment="Top"/>
<TextBlock FontSize="16" Foreground="Red" HorizontalAlignment="Left" Margin="10,424,0,0" Grid.Row="1" TextWrapping="Wrap" Text="當前觸碰點相對於初次觸碰點的坐標偏移:" VerticalAlignment="Top"/>
<TextBlock Foreground="Red" HorizontalAlignment="Left" Margin="97,440,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Y:" VerticalAlignment="Top"/>
<TextBlock Text="0" x:Name="tx" Foreground="Red" HorizontalAlignment="Left" Margin="29,440,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock Text="0" x:Name="ty" Foreground="Red" HorizontalAlignment="Left" Margin="115,440,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock FontSize="16" Foreground="DarkKhaki" HorizontalAlignment="Left" Margin="10,489,0,0" Grid.Row="1" TextWrapping="Wrap" Text="初次主次觸控點相對於被觸控控件基准點的坐標:" VerticalAlignment="Top"/>
<TextBlock Text="Null" x:Name="pa" Foreground="DarkKhaki" HorizontalAlignment="Left" Margin="10,511,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock FontSize="16" Foreground="Fuchsia" HorizontalAlignment="Left" Margin="10,535,0,0" Grid.Row="1" TextWrapping="Wrap" Text="初次主次觸控點相對於被觸控控件基准點的坐標:" VerticalAlignment="Top"/>
<TextBlock Text="Null" x:Name="pb" Foreground="Fuchsia" HorizontalAlignment="Left" Margin="10,553,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock FontSize="16" Foreground="CadetBlue" HorizontalAlignment="Left" Margin="10,583,0,0" Grid.Row="1" TextWrapping="Wrap" Text="當前主次觸控點間距÷初次主次觸碰點間距:" VerticalAlignment="Top" />
<TextBlock Text="Null" x:Name="pc" Foreground="CadetBlue" HorizontalAlignment="Left" Margin="10,596,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock FontSize="16" Foreground="Aqua" HorizontalAlignment="Left" Margin="10,625,0,0" Grid.Row="1" TextWrapping="Wrap" Text="當前主次觸控點間距÷初次主次觸碰點間距:" VerticalAlignment="Top" />
<TextBlock Text="Null" x:Name="pd" Foreground="Aqua" HorizontalAlignment="Left" Margin="10,642,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top"/>
</Grid>
</phone:PhoneApplicationPage>
[C#]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using PhoneApp1.Resources;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Shapes;
using Microsoft.Xna.Framework.Input.Touch;
namespace PhoneApp1
{
public partial class MainPage : PhoneApplicationPage
{
private CompositeTransform compositeTransform = new CompositeTransform();
private Brush startBgColor;
private Brush bgColor = new SolidColorBrush(Colors.Orange);
//觸碰初始被觸碰控件本身平移量
double startX;
double startY;
//初次觸碰點相對於被拖動控件基准點的坐標
double firstTranslateX;
double firstTranslateY;
public MainPage()
{
InitializeComponent();
rectangle.RenderTransform = compositeTransform;
//設置可識別的手勢,必須設置才能被啟用
TouchPanel.EnabledGestures = GestureType.Hold | GestureType.Tap | GestureType.DoubleTap | GestureType.Flick | GestureType.Pinch;
//觸控開始時發生
rectangle.ManipulationStarted += new EventHandler<ManipulationStartedEventArgs>(Rectangle_ManipulationStarted);
//觸控過程中位置變更時發生
rectangle.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(Rectangle_ManipulationDelta);
//觸控結束時發生
rectangle.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(Rectangle_ManipulationCompleted);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
//獲取設備對觸控的支持性
var a = TouchPanel.GetCapabilities();
//當前設備是否支持觸控
if (a.IsConnected)
{
//當前設備支持幾個觸控點
CapabilitiesText.Text = "當前設備支持[ "+a.MaximumTouchCount+" ]點觸控";
}
base.OnNavigatedTo(e);
}
void Rectangle_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
startBgColor = rectangle.Fill;
(e.ManipulationContainer as Rectangle).Fill = bgColor;
//這兩個值效果一樣,都是指被觸控控件本身
//(e.OriginalSource as Rectangle).Fill = endBgColor;
//觸碰初始被觸碰控件本身平移量
startX = compositeTransform.TranslateX;
startY = compositeTransform.TranslateY;
//初次觸碰點相對於被拖動控件基准點的坐標
firstTranslateX = e.ManipulationOrigin.X;
firstTranslateY = e.ManipulationOrigin.Y;
}
void Rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
//當前觸碰點相對於被觸控控件基准點的坐標
ox.Text = ConvertString(e.ManipulationOrigin.X);
oy.Text = ConvertString(e.ManipulationOrigin.Y);
//當前觸碰點相對於上一觸碰點的坐標偏移
dx.Text = ConvertString(e.DeltaManipulation.Translation.X);
dy.Text = ConvertString(e.DeltaManipulation.Translation.Y);
//當前觸碰點相對於初次觸碰點的坐標偏移
tx.Text = ConvertString(e.CumulativeManipulation.Translation.X);
ty.Text = ConvertString(e.CumulativeManipulation.Translation.Y);
//控件跟隨移動
//compositeTransform.TranslateX += e.DeltaManipulation.Translation.X;
//compositeTransform.TranslateY += e.DeltaManipulation.Translation.Y;
//實時精准定位移動,不考慮連貫性
//compositeTransform.TranslateX += e.DeltaManipulation.Translation.X + e.ManipulationOrigin.X - firstTranslateX;
//compositeTransform.TranslateY += e.DeltaManipulation.Translation.Y + e.ManipulationOrigin.Y - firstTranslateY;
//相對於上次的縮放量
//if (e.DeltaManipulation.Scale.X > 0 && e.DeltaManipulation.Scale.Y > 0)
//{
// compositeTransform.ScaleX *= e.DeltaManipulation.Scale.X;
// compositeTransform.ScaleY *= e.DeltaManipulation.Scale.Y;
//}
if (e.PinchManipulation != null)
{
//初次主次觸控點相對於被觸控控件基准點的坐標
pa.Text = ConvertString(e.PinchManipulation.Original.PrimaryContact)
+ " " + ConvertString(e.PinchManipulation.Original.SecondaryContact)
+ " " + ConvertString(e.PinchManipulation.Original.Center);
//當前主次觸控點相對於被觸控控件基准點的坐標
pb.Text = ConvertString(e.PinchManipulation.Current.PrimaryContact)
+ " " + ConvertString(e.PinchManipulation.Current.SecondaryContact)
+ " " + ConvertString(e.PinchManipulation.Current.Center);
//當前主次觸控點間距÷初次主次觸碰點間距
pc.Text = ConvertString(e.PinchManipulation.CumulativeScale);
//當前主次觸控點間距÷上一主次觸碰點間距
pd.Text = ConvertString(e.PinchManipulation.DeltaScale);
}
//全部觸控點的絕對坐標和狀態
TouchCollection touchCollection = TouchPanel.GetState();
string stateString = string.Empty;
foreach (var item in touchCollection)
{
stateString += " " + item.Position.ToString() + "[" + item.State.ToString() + "]";
}
TouchCollectionText.Text = stateString;
}
void Rectangle_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
rectangle.Fill = startBgColor;
//當手勢可用時執行
while (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
//獲取當前的識別的手勢類型
p.Text = gesture.GestureType.ToString();
}
}
private string ConvertString(double value)
{
return (Math.Round(value * 100) / 100).ToString();
}
private string ConvertString(Point value)
{
return "{" + (Math.Round(value.X * 100) / 100).ToString() + "," + (Math.Round(value.Y * 100) / 100).ToString() + "}";
}
}
}
關於WP8模擬器多點觸控
最后,我啰嗦一下,有些朋友沒有WP8手機,但是這里卻要用到多點觸控,可是WP8模擬器卻不支持,怎么辦呢,本人首先想到尋找一個虛擬鼠標的軟件,但是發現很難實現,其實WIN8模擬器支持多點觸控,我們可以在WIN8模擬器中打開WP8模擬器,這樣就可以利用WIN8模擬器的多點觸控功能了.
出處:[ http://www.cnblogs.com/lipan/]
版權聲明:本文的版權歸作者與博客園共有。轉載時須注明原文出處以及作者,並保留原文指向型鏈接,不得更改原文內容。否則作者將保留追究其法律責任。
