今天介绍触摸屏点击
从硬件设计上说Windows Phone 7至少可以接收4个手指的触摸事件。
一、在XNA上的Low-Level触摸事件
可以利用全局的TouchPanel class来的到输入事件。
-----------------------------
Tips:
1. 调用静态的TouchPanel.GetCapabilities()方法返回TouchPanelCapabilities的可以的到系统的输入能力。
TouchPanelCapabilities对象中:
IsConnected表示触摸是否可用。
MaximumTouchCount表示最多可响应几个触点。
2. 在Update()函数中,调用TouchPanel.GetState()方法来的到TouchCollection对象来的到当前的按键情况。
3. 得到的TouchCollection对象中有0到多个TouchLocation对象,包含单个触点对象的信息。
TouchLocation对象中:
TouchLocationState State:Pressed, Moved, Released
Vector2 Position:表示触点针对左上角的位置
int id:表示在一次触摸过程中的唯一标识(从按下开始分配这个ID,在抬起事件结束前这个ID不会变)
bool TryGetPreviousLocation(out TouchLocation)方法,可以得到上一次刷新的触点对象。(可以用来算位移差值,没有上一个位置的话函数会返回false)
注意:在Pressed事件过后,就算手指没有移动也会接收到Moved事件,直到手指抬起触发Released事件。
如果点击得特别快在两次刷新之间完成了按下和抬起,是收不到Moved事件的。
手指这个东东比较粗,有可能你按一下下会产生多个Pressed事件,处理的时候还要考虑按键区域的问题。不要重复计算多个区域的好。
------------------------------
二、XNA下的手势接口
这个比刚才那个高级了。
直接利用TouchPanel.EnabledGestures设置你需要监听的手势,然后在Update()中,通过查询属性TouchPanel.IsGestureAvailable,得到当前是否有需要的手势状态并做处理。
------------------------------
Tips:
1. TouchPanel.EnabledGestures可以设置的动作有Tap, DoubleTap, Flick, Hold, Pinch, PinchComplete, FreeDrag, HorizontalDrag, VerticalDrag 和 DragComplete,他们之间可以用与运算连接同时设置多个动作。
2. 在Update()中读取手势的方法:
protected override void Update(GameTime gameTime)
{
…
while(TouchPanel.IsGestureAvailable)
{
//得到一个动作取样
GestureSample gestureSample = TouchPanel.ReadGesture();
if (gestureSample.GestureType == GestureType.Tap)
{
//…………………………
}
else if (gestureSample.GestureType == ……….)
{
//…………………………
}
}
}
注意:手势事件是在确实触发了这种事件后才执行的,因此Tap是在手指离开屏幕才处理的。
有些手势会有前置动作,GestureSample中的Position2和Delta2就起了作用。
----------------------------
三、在Silverlight上的Low-Level触摸事件
在Silverlight上,可以通过静态事件Touch.FrameReported回调事件响应函数。
--------------------------
Tips:
1. 将回调函数添加到事件中。
Touch.FrameReported += OnTouchFrameReported;
回调函数的实现类似于:
void OnTouchFrameReported(object sender, TouchFrameEventArgs args) {
…
}
TouchFrameEventArgs对象中包含:
GetTouchPoints(refElement) 返回一个 TouchPointCollection(也就是一组TouchPoint,参数传null的话,返回从左上角开始的所有触点内容)
GetPrimaryTouchPoint(refElement) 返回一个 TouchPoint(第一个触摸事件)
SuspendMousePromotionUntilTouchUp()禁止该事件被提升为鼠标事件,这个函数可有渊源等下详细介绍。
GetTouchPoints和GetPrimaryTouchPoint返回的都是和TouchPoint相关的。
那就先说说TouchPoint对象:
TouchAction Action:Down, Move, 和 Up.
Point Position:这个就是针对左上角的坐标了。
Size Size:触摸的区域大小(在WP7上没啥用)
TouchDeivce TouchDeivce:这个是个对象里面包含:int Id,从触点按下到抬起的唯一标识。UIElement DirectlyOver,按键底下的控件,也就是谁不幸被点了。
SuspendMousePromotionUntilTouchUp(),禁止该时间被提升为鼠标事件,得解释一下,这个方法来自桌面的Silverlight,很多桌面程序只有鼠标按键,现在有触摸屏了,点一下触摸屏,一小下,就不好区分,这个事件是鼠标点的还是触控事件呢?这个函数就是在处理触控的时候防止同时触发鼠标的点击事件。因此,这个函数只能在,只有在处理第一个触摸事件,并且是在处理按下事件的时候才能调用。否则~~哼哼,会抛出异常。下面是个调用的例子。
void OnTouchFrameReported(object sender, TouchFrameEventArgs args)
{
TouchPoint primaryTouchPoint = args.GetPrimaryTouchPoint(null);//第一个触点,并且是按下事件
if (primaryTouchPoint != null && primaryTouchPoint.Action == TouchAction.Down)
{
args.SuspendMousePromotionUntilTouchUp();
}
…}
-----------------------------
四、操作事件(The Manipulation Events)
Silverlight的高级操作接口。由三个事件组成ManipulationStart、ManipulationDelta、MannipulationCompleted。
-----------------------------
Tips:
1. 在xaml中,这三个事件可以作为控件的属性添加到控件中。
2. 三个方法ManipulationStart、ManipulationDelta、ManipulationCompleted,分别对应触摸操作的按下,移动,抬起三个事件。并且在出发ManipulationStart事件到ManipulationCompleted结束之间,就算有其他触摸,事件也不会被响应。
3. 在回调中调用args.Complete()方法,会在执行完当前回调后立即触发ManipulationCompleted这个事件。
4. 继承PhoneApplicationPage的窗口可以重载ManipulationStart、ManipulationDelta、ManipulationCompleted这三个方法。注意到在参数对象ManipulationStartedEventArgs args中,args.OriginalSource标志的是页面上触摸的控件。
----------------------------
五、操作事件的执行路径
现在,控件上可以有三个操作的回调,页面上可以有三个操作的重载。他们的执行路径会是什么样的呢?
场景:
在Page上有一个TextBlock,现在用户在TextBlock点了一下。
以ManipulationStart事件为例:Silverlight框架会先执行TextBlock上的回调,然后执行Page重载的方法。
但是当执行TextBlock上的回调时,设置了args.Handled为true,这样消息就不会传递给上层Page了。
延伸:
有个比较有意思的事情,TextBlock上的ManipulationStart执行时执行了args.Complete(),并且设置了args.Handled为true,同时不对ManipulationComplete中的args做操作。上层Page收不到OnManipulationStart的事件了,可是可以执行OnManipulationComplete重载。结论是这三个事件之间是并行没有关联的。
其实也好理解,分别实现三个事件比三个事件关联容易多了,框架也更整齐。写Silverlight的人也是参考了一些游戏框架的消息处理机制的。