第16天 Android Touch事件学习 3 区分各种手势基础知识
来源:互联网 发布:python while循环列表 编辑:程序博客网 时间:2024/05/29 16:14
触摸事件学习系列文章详见:
《Android Touch事件学习系列汇总》
之前分析点击事件从view.setOnClickListener源码一路查找,发现最终处理的地方是在onTouchEvent,但是仅仅获取到这些信息还是无法解释对于触屏事件的理解,还是会有很多疑惑,而且点击事件也没有完全的解读,不着急一点点来,先来看看一下疑问:
如何区分各种触屏手势?
如何区分手指在当前哪个视图内(例如:手指是点击按钮,还是点击屏幕上列表中某一项)?
何处调用onTouchEvent方法?(这个问题先暂时存着,之后会涉及到,先一步步解决其他疑惑)
现在尝试着从之前获取的信息onTouchEvent上,看能否有哪些蛛丝马迹可以解决以上问题的没有,首先来看下Android View类的文档中对此方法的定义,
public boolean onTouchEvent (MotionEvent event)
发现这个方法会传递一个MotionEvent 类型的对象,文档中对于此类的解释是:MotionEvent用于提供各种运动事件信息(鼠标、触屏笔、手指、轨迹球),更详细信息可以查看文档《MotionEvent》。下面就来说下我从MotionEvent中获取的解决以上疑问的答案。
一、如何区分各种手势?
如果使用过智能手机,准确点是支持触摸屏幕的智能手机,与之前手机的最大区别就是所有操作不需要键盘和鼠标,对手机进行操作是手指在屏幕上触摸作为输入命令,站在系统的角度思考一下,用户仅仅手指接触屏幕系统如何知道用户想做什么呢?用户到底是点击、长按、滚动、还是双击呢? 这些操作可以统称为手势。
MotionEvent提供一个getAction()方法其目的是返回当前正在执行的操作,具体有哪些操作呢?Android MotionEvent中定义了最少10中不同的action并且可以区分是一只手指在屏幕上操作(单点触摸)和多个手指在屏幕上操作(多点触摸),这里先仅简单介绍下单点触摸,这种是最常用的,如果感兴趣可以自己了解下多点触摸的相关知识,我个人也有整理一些但是感觉还有些疑惑,反正多点触摸一边玩去吧,不是今天的主角以后再说。
Action有很多如果想了解所有的可以去查看文档《MotionEvent》其中“Constants”一栏中所有已ACTION_开头的都是系统支持的Action。这里介绍最简单最常用的5个分别是:
ACTION_DOWN、ACTION_MOVE、ACTION_UP、ACTION_CANCEL 和 ACTION_OUTSIDE
都啰嗦这么多了,在这个信息爆炸式增长的年代,流行眼见为实毕竟不证实下谁知道是真是假的,是骡子是马拉出来溜溜,来吧直接上图
下面是触发ACTION_DOWN、ACTION_MOVE、ACTION_UP例子图片:
我个人不太喜欢贴源码,但是有的时候我自己都懒得打开项目再看看,干脆还是把demo的源码贴出来吧
public class MainActivity extends Activity {// ===========================================================// Constants// ===========================================================// ===========================================================// Fields// ===========================================================private LinkedHashMap<String, Integer> mHashMap = new LinkedHashMap<String, Integer>();private OnLogListener mOnLogListener;// ===========================================================// Constructors// ===========================================================// ===========================================================// Public Methods// ===========================================================// ===========================================================// Methods for/from SuperClass/Interfaces// ===========================================================@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initLog(); initCancelButton();initTouchListener(); }private void initLog() {final TextView output = (TextView) findViewById(R.id.txt_output); // 初始化Log监听器 mOnLogListener = new OnLogListener() {@Overridepublic void output(String outputValue) {output.setText( outputValue );}}; // 初始化输出信息状态initState();}private void initCancelButton() {final CustomFrameLayout layout = (CustomFrameLayout) findViewById(R.id.layout_touch);final Button button = (Button) findViewById(R.id.btn_cancel); button.setText("是否触发ACTION_CANCEL : " + layout.getExecuteCancel()); button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {boolean executeCancel = layout.getExecuteCancel();layout.setExecuteCancel(!executeCancel);button.setText("是否触发ACTION_CANCEL : " + !executeCancel);}});}private void initTouchListener() {// 设置中间图片视图的触摸事件View view = findViewById(R.id.view_touch_two);view.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) {case MotionEvent.ACTION_DOWN:initState();updateState("ACTION_DOWN");break;case MotionEvent.ACTION_MOVE:updateState("ACTION_MOVE");break;case MotionEvent.ACTION_UP:updateState("ACTION_UP");break;case MotionEvent.ACTION_CANCEL:updateState("ACTION_CANCEL");break;case MotionEvent.ACTION_OUTSIDE:updateState("ACTION_OUTSIDE");break;default:break;} return true;}});}// ===========================================================// Private Methods// =========================================================== private void initState() { if (mHashMap != null) { mHashMap.put("ACTION_DOWN", 0); mHashMap.put("ACTION_MOVE", 0); mHashMap.put("ACTION_UP", 0); mHashMap.put("ACTION_CANCEL", 0); mHashMap.put("ACTION_OUTSIDE", 0);} updateState(""); } private void updateState(String pActionName) {if (!TextUtils.isEmpty(pActionName)) {int value = mHashMap.get( pActionName );mHashMap.put(pActionName, ++value);}StringBuilder outputStr = new StringBuilder();Set<Entry<String, Integer>> entrySet = mHashMap.entrySet();for (Iterator<Entry<String, Integer>> iterator = entrySet.iterator(); iterator.hasNext();) {Entry<String, Integer> entry = (Entry<String, Integer>) iterator.next();outputStr.append("\n");outputStr.append("Action Name = ");outputStr.append(entry.getKey());outputStr.append(", 触发次数 = ");outputStr.append(entry.getValue());}mOnLogListener.output(outputStr.toString());}private interface OnLogListener {public void output(String output);} // ===========================================================// Inner and Anonymous Classes// =========================================================== }
覆写onTouchEvent方法,获得MotionEvent对象,从MotionEvent中可以获取到action,通常touch事件中都会针对一些操作做些处理,这里打印出log看看action执行规律.
从例子执行的图中可以看出down和up仅在滑动事件开始和结束的时候个执行一次,move在滑动过程中执行多次
下面是触发ACTION_CANCEL例子图片:
再来看看布局文件
<?xml version="1.0" encoding="utf-8"?><touch.two.action.CustomFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/layout_touch" > <TextView android:id="@+id/txt_output" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <View android:id="@+id/view_touch_two"android:layout_width="100dip"android:layout_height="100dip"android:layout_gravity="center"android:background="@drawable/ic_launcher" /><Button android:id="@+id/btn_cancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|bottom" /></touch.two.action.CustomFrameLayout>
使用的是自定义layout视图,目的是为了拦截子视图移动动作触发cancel,以下是自定义视图源码:
public class CustomFrameLayout extends FrameLayout {public CustomFrameLayout(Context context) {super(context);}public CustomFrameLayout(Context context, AttributeSet attrs) {super(context, attrs);}public CustomFrameLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}private boolean mExecuteCancel = false;public void setExecuteCancel(boolean flag) {mExecuteCancel = flag;}public boolean getExecuteCancel() {return mExecuteCancel;}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (MotionEvent.ACTION_MOVE == ev.getAction()) {return mExecuteCancel;}return super.onInterceptTouchEvent(ev);}}
从上图可以得出以下结论:
1. ACTION_DOWN与 : 在一次操作中仅会触发一次,是在手指刚接触屏幕时触发
2. ACTION_UP : 在一次操作中仅会触发一次,是在手指离开屏幕时触发
3. ACTION_MOVE:操作过程中会有0个、1个或者多个ACTION_MOVE,如果手指一直在屏幕上移动,就会一直触发ACTION_MOVE,而且都是在ACTION_DOWN之后与ACTION_UP之前
4. ACTION_CANCEL:再来说说这个比较特别的不太容易触发,例子里面是我添加一个按钮来开关是否执行此ACTION。
子视图执行ACTION_DOWN时父视图oninterceptTouchEvent 返回false,当子视图执行ACTION_MOVE时父视图onInterceptTouchEvent 返回true,此时子视图会接收到ACTION_CANCEL。
如果偶尔翻看Android View onTouchEvent源码的话,会发现里面对 ACTION_UP与ACTION_CANCEL基本一致都是进行事件清理操作,有些干脆执行相同的操作,所以对于这个ACTION只需要了解什么时候出发,至于该哪些操作干脆和ACTION_UP处理逻辑一样即可。
简单一句话总结ACTION_CANCEL是父视图接管子视图控制权时使用。
5. ACTION_OUTSIDE:文档说是在UI元素之外触发。未找到何处使用,以下四种都尝试了
(1)在子视图设置事件,在其中移动并滑动到其他视图,不会触发
(2)在Dialog视图中设置事件,在其中移动并滑动到Dialog外,不会触发
(3)在WindowManager视图内设置事件,在其视图内滑动到视图外,不会触发
(4)在View与ViewGroup类中都未搜索到“ACTION_OUTSIDE”相关的代码
总之Android系统把人类的触摸行为分类很多种动作(ACTION),单点触摸分别为ACTION_DOWN、ACTION_MOVE、ACTION_UP、ACTION_CANCEL 和 ACTION_OUTSIDE,而且这些信息可以从MotionEvent.getAction()获取,一些系统支持的手势是在相应视图的onTouchEvent中通过这些动作上添加判断获得,如果自定义视图也需要灵活是用这些动作,当然这里仅仅是解释系统提供了哪些信息便于分别各种手势,如何判断手势与这些ACTION具体从哪来的之后再慢慢分析学习。
当前仅解决了一个疑惑,下一篇文章接着解决下一个问题“如何区分手指在当前哪个视图内(例如:手指是点击按钮,还是点击屏幕上列表中某一项)?”
- 第16天 Android Touch事件学习 3 区分各种手势基础知识
- 第19天 Android Touch事件学习 6 手势识别
- 第14天 Android Touch事件学习 1 点击事件
- Android 手势&触摸事件。手势各种状态
- Android的Touch事件处理和手势
- 第15天 Android Touch事件学习 2 触发点击事件的地方
- 第20天 Android Touch事件学习 7 交给哪个视图处理事件?
- 第21天 Android Touch事件学习 8 事件分发原理
- 第17天 Android Touch事件学习 4 获取手指触摸位置
- 第18天 Android Touch事件学习 5 点击与长按原理
- Android基础之Touch事件和手势处理
- js中的touch事件及gesture(手势)事件详解 — 第13.4.9节
- js touch事件 手势滑动事件总结
- Android Touch事件学习系列汇总
- Android学习之 Touch事件传递机制
- Android Touch事件分发机制学习
- android的Touch事件传递机制学习
- Android中touch事件机制学习总结
- Hadoop到底能做什么?怎么用hadoop? 与 R语言简介 以及 MapReduce
- hadoop中使用MapReduce编程实例
- ntp服务器和客户端配置(centos安装系列5)
- 2014年测绘地理信息工作要点---------------国家测绘地理信息局
- 右键新建菜单不见了
- 第16天 Android Touch事件学习 3 区分各种手势基础知识
- 找不到合适的驱动
- HDU 2566 统计硬币。
- [MST]POJ 1258Agri-Net
- 阿里云服务器的80端口被封了么?
- javascript的中文传参
- 1039. Course List for Student (25)
- <MEMORY>Project Euler NO55
- 【深入浅出Objective-C】8.3字典(NSMutableDictionary)