Windows 10 开发日记(三)-- 如何在手势开始之前判断手指数量
这是我们在实际项目中经常要面临的问题,因为你很可能会出现这种需求:单手操作与双手操作的行为不同,在手势开始之时就需要知道到底是单手还是双手。
方案一:
了解了这个需求之后,我迅速凭借经验,感觉在ManipulationStarting或者ManipulationStarted事件传入的参数中应该类似于e.GetPointers()类似的方法,用于获得当前有多少个手指在屏幕上。感觉三年的Windows 开发经验终于有了点小用,节省了我好多效率不免心生有预感。。。但是当寻找了半天之后,胸中顿时有几万只草泥马奔腾而过,不是说的是底层事件吗?底层事件连最简单的判断有几个手指头都不行么?TouchFrame才叫底层事件好吗???
public class ManipulationStartedRoutedEventArgs : RoutedEventArgs, IManipulationStartedRoutedEventArgs { public ManipulationStartedRoutedEventArgs(); public UIElement Container { get; } public ManipulationDelta Cumulative { get; } public System.Boolean Handled { get; set; } public PointerDeviceType PointerDeviceType { get; } public Point Position { get; } public void Complete(); }
各位请看,我不会冤枉好人的,根本就没有一个集合性的东西,这个Point倒是手指在屏幕上的接触点,但是这都是Started事件了好么?我要的是在Started之前就知道有几个手指头跟屏幕接触好么?
方案二:
抱着”微软虐我千百遍,我待微软如初恋"的心态,我继续寻找方案二。心想:如果我能获得这个容器,甚至我获取这个App所在的Frame,应该有暴露方法判断有多少个手指吧。具体的过程我就不说了,神马UIElement,Control,Frame,都没有啊,都没有。
方案三:
抱着“人在屋檐下,不得不低头”的心态,我继续寻找方案三,(毕竟技术是你微软的,项目是我的,还得继续啊,一万只草泥马又呼啸而来。。。),去MSDN上面扒了扒跟输入相关的知识点,终于发现了一个东西,并且是一个比较熟悉的东西:PointerPressed,中级事件,这个事件我们上篇已经做过实验了,它会在ManipulationStarting之前触发,就是说,如果我在这个事件触发之时,能获取手指的个数,那我就能解决这个问题了!(https://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj150606.aspx, 这篇文章详细介绍了Pointer相关的知识,有兴趣的朋友可以去看看,草泥马统统不见了,前途一片光明啊,哈哈哈)
可以这么说,每一次点击都会触发一次PointerPressed事件,并且这个事件带来的参数能够获得接触点的信息,这个信息包含了PointerID,就是说,每一次点击,系统会标识这个接触点,松开后系统回收这个标记,那么我们本地可以实现一个字典,以PointerID为key,对应的Pointer为Value,那么在OnManipulationStarting事件中我就能判断是几个手指啦,说干就干
private Dictionary<uint, Point?> _contacts; //与屏幕接触的点的集合 /// <summary> /// 手指按下 /// </summary> /// <param name="e"></param> protected override void OnPointerPressed(PointerRoutedEventArgs e) { //if (e.Pointer.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse) //{ _contacts[e.Pointer.PointerId] = e.GetCurrentPoint(this).Position; //} e.Handled = true; } /// <summary> /// 手指离开 /// </summary> /// <param name="e"></param> protected override void OnPointerReleased(PointerRoutedEventArgs e) { //if (e.Pointer.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse) //{ if (_contacts.ContainsKey(e.Pointer.PointerId)) { _contacts[e.Pointer.PointerId] = null; _contacts.Remove(e.Pointer.PointerId); } //} e.Handled = true; } /// <summary> /// 手指放上只会出发starting事件,要移动才开始触发started事件 /// </summary> /// <param name="e"></param> protected override void OnManipulationStarted(ManipulationStartedRoutedEventArgs e) { int count = _contacts.Count; if (count == 1) {// 如果这时手指只有一根,则认为在对比模式 _viewController.OnManipulationStarted(e); } else if (count > 1) {// 如果手指超过一根,则认为在缩放模式下 e.Handled = true; } }
哇哈哈哈哈,到了这个时候,功能做完了,是时候回过头来看看,为什么ManipulationStarting不能提供GetPoints()的方法。从实验的结果来看,ManipulationStarting应该还是只针对单次操作来说的,又或者说,ManipulationStarting只是一个“预备”的动作,并不能做很多事情。但是ManipulationDelta又可以判断双手操作中的:Scale,额,这个要在以后慢慢琢磨了。
如果你也遇到了在操作之前判断手指的情况,这篇文章对你应该会有帮助。
手势部分就到此,因为我在项目中也仅仅遇到了这些问题,不排除后续还有更复杂的情况出现,或者又扩展了很多其他问题。