Android 触摸手势基础 官方文档概览

采得百花成蜜后,为谁辛苦为谁甜。这篇文章主要讲述Android 触摸手势基础 官方文档概览相关的知识,希望能为你提供帮助。
触摸手势检测基础手势检测一般包含两个阶段:
1.获取touch事件数据
2.解析这些数据,看它们是否满足你的应用所支持的某种手势。
相关API:
MotionEvent
兼容版的:
MotionEventCompat 
(Note that MotionEventCompat is not a replacement for the MotionEvent class. Rather, it provides static utility methods to which you pass your MotionEvent object in order to receive the desired action associated with that event.)
 
一般的Activity或View中的touch事件处理Activity或View类的onTouchEvent()  回调函数会接收到touch事件。
为了截获touch事件,你需要覆写Activity或View的onTouchEvent方法。
 
View中还可以使用setOnTouchListener()方法添加点击事件的  View.OnTouchListener  监听对象。这样就可以不继承View而处理点击事件。
但是如果需要处理双击、长按、fling(快滑)等手势,你需要利用  GestureDetector类。
 
onTouchEvent方法的返回值onTouchEvent方法的返回值,如果返回true,意味着你已经处理过了touch事件;如果返回false,将会继续通过view stack传递事件,直到事件被处理。
这里需要注意  ACTION_DOWN  事件,如果返回false,则该listener将不会被告知后面的一系列  ACTION_MOVE和  ACTION_UP  事件。
 
检测手势android提供了GestureDetector  类来检测一般的手势。
基本使用:
1.生成GestureDetector  对象(或GestureDetectorCompat对象),构造时的参数传入监听器对象。
监听器对象实现GestureDetector.OnGestureListener  接口。
如果你仅仅是想利用其中的一些手势而不是全部,那么你可以选择继承GestureDetector.SimpleOnGestureListener类,这是一个适配器模式,即这个类实现了GestureDetector.OnGestureListener  接口,为其中所有的方法提供了空实现(返回值都是false),当继承GestureDetector.SimpleOnGestureListener类时,子类只需要覆写感兴趣的方法,其他方法是空实现。
2.为了让  GestureDetector对象接收到事件,需要覆写View或Activity中的  onTouchEvent()方法,将事件传递给detector对象。
一个例子:
HelloGestureDetectorActivity.java 
 
根据官网上说:
关于onDown()方法的返回值,最好是返回true,因为所有的手势都是从onDown()信息开始的。
如果像  GestureDetector.SimpleOnGestureListener  默认实现一样返回false,系统就会认为你想要忽略之后的其他手势,然后GestureDetector.OnGestureListener  的其他方法就不会被调用。
但是实际程序验证的时候,发现返回true还是false好像没有什么影响。(??)
 
跟踪运动 速度有很多不同的方法来记录手势中的运动,比如pointer的起始位置和终止位置;pointer运动的方向;手势的历史(通过  getHistorySize()方法得到);还有pointer的运动速度。
Android提供了VelocityTracker  类和VelocityTrackerCompat类,来记录touch事件的速度。
代码例子:
Tracking Velocity 
滚动手势如果一个标准的布局有可能会超出它的容器的边界,可以把它嵌套在一个ScrollView中,这样就会得到一个可以滚动的布局,由framewok处理。
实现一个自定义的scroller应该只在一些特殊情况下需要。
Scroller用来随时间制造滚动动画,使用平台标准的滚动物理参数(摩擦力、速度等)。
Scroller自己本身实际上并不绘制任何东西。
Scroller记录滚动的偏移值,但是它并不会将这些位置应用到你的View,你需要自己动手。
详见:http://developer.android.com/training/gestures/scroll.html
 
多点触摸手势当多个pointer同时触摸屏幕,系统会生成如下事件:

  • ACTION_DOWN— For the first pointer that touches the screen. This starts the gesture. The pointer data for this pointer is always at index 0 in the  MotionEvent.
  • ACTION_POINTER_DOWN— For extra pointers that enter the screen beyond the first. The pointer data for this pointer is at the index returned by  getActionIndex().
  • ACTION_MOVE— A change has happened during a press gesture.
  • ACTION_POINTER_UP— Sent when a non-primary pointer goes up.
  • ACTION_UP— Sent when the last pointer leaves the screen.
你可以依靠每一个pointer的index和ID来追踪每一个pointer:
Index:MotionEvent会把每一个pointer的信息放在一个数组里,index即是这个数组索引。大多数你用的MotionEvent方法是以这个index作为参数的。
ID:每一个pointer还有一个ID映射,在touch事件中保持恒定一致(persistent),这样就可以在整个手势中跟踪一个单独的pointer。
 
pointer在一个motion event中出现的顺序是未定的,所以pointer的index在不同的事件中是可变的,但是只要pointer保持active,它的ID是保持不变的。
通过getPointerId()获得ID,这样就可以在多个motion event中追踪pointer。然后对于连续的motion event,可以使用findPointerIndex()方法来获得指定ID的pointer在当前事件中的index。
比如:
 
private int mActivePointerId; public boolean onTouchEvent(MotionEvent event) { .... // Get the pointer ID mActivePointerId = event.getPointerId(0); // ... Many touch events later...// Use the pointer ID to find the index of the active pointer // and fetch its position int pointerIndex = event.findPointerIndex(mActivePointerId); // Get the pointer‘s current position float x = event.getX(pointerIndex); float y = event.getY(pointerIndex); }

   
 
获取MotionEvent的动作应该使用getActionMasked()方法(或者是兼容版的MotionEventCompat.getActionMasked())。
与旧版的getAction()不同,getActionMasked()  方法是被设计为可以多个pointer工作的。
它会返回带掩模的动作,不带pointer用于index的那些位。
你可以使用getActionIndex()来得到index。
 
拖动和缩放拖动一个对象:
【Android 触摸手势基础 官方文档概览】如果是Android 3.0以上,可以使用View的新接口View.OnDragListener参见:Drag and Drop。
其他参见:http://developer.android.com/training/gestures/scale.html
 
缩放可以使用  ScaleGestureDetector
ScaleGestureDetector可以和GestureDetector一起使用。
  ViewGroup中的Touch事件处理处理  ViewGroup的touch事件要麻烦一些,因为很可能各种touch事件的目标不是ViewGroup而是它的child。
为了确保每一个child正确地接收到touch events,需要覆写ViewGroup的onInterceptTouchEvent()方法。
 
如果onInterceptTouchEvent()方法返回true,说明MotionEvent被截获了,它将不会被传递给child,而是传递给parent的  onTouchEvent()方法。
如果你在parent的onInterceptTouchEvent()方法中返回了true,先前还在处理touch event的child view将会接收到一个  ACTION_CANCEL,之后的事件就会全传递到parent的onTouchEvent中。
如果  onInterceptTouchEvent()  方法返回false,则事件继续顺着view结构向下传递,parent不会截获事件,也不会调用parent的onTouchEvent()方法。
 
另:
ViewConfiguration提供一些常量。
TouchDelegate类可以用来设置View的触摸区域。
用法见:http://developer.android.com/training/gestures/viewgroup.html
 
参考资料Training: Using Touch Gestures
http://developer.android.com/training/gestures/index.html

    推荐阅读