采得百花成蜜后,为谁辛苦为谁甜。这篇文章主要讲述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 theMotionEvent
.ACTION_POINTER_DOWN
— For extra pointers that enter the screen beyond the first. The pointer data for this pointer is at the index returned bygetActionIndex()
.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.
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
推荐阅读
- Android样式之selector
- 通过VMwarek可以安装Android_x86
- 札记(android手势识别,MotionEvent)
- Android笔记——Android中visibility属性VISIBLEINVISIBLEGONE的区别
- Android——提升ListView的运行效率
- Android知识——ViewHolder的作用与用法
- Android进程间的通信之Messenger
- Android笔记——permission权限大全
- Android中的AlertDialog使用示例四(多项选择确定对话框)