Android 中Touch(触屏)事件传递机制
Posted wuhongqi0012
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 中Touch(触屏)事件传递机制相关的知识,希望对你有一定的参考价值。
转载来自:http://blog.csdn.net/wangjinyu501/article/details/22584465
版本:2.0 日期:2014.3.21 2014.3.29 版权:© 2014 kince 转载注明出处一、基本概念
在实际开发中,经常会遇到与触屏事件有关的问题,最典型的一个就是滑动冲突。比如在使用SliddingMenu菜单的时候,可能会与ViewPager或者其他的一些带有滑动事件的View相冲突,再比如ScrollView嵌套ListView相冲突等等。还有就是在自定义控件的时候,需要处理一些事件时候,也必须把逻辑处理好,父 view 和子view 都需要接收事件,然后处理。如果不明白事件传递机制,很难开发出需要的效果。因此就需要对android消息传递机制有一个基本的理解与认识,这样才有可能解决开发过程中的需求与问题。 对于触摸(Touch)触发的事件,在Android中,事件主要包括点按(onClick)、长按(onLongClick)、拖拽(onDrag)、滑动(onScroll)等,点按又包括单击和双击,另外还包括单指操作和多指操作。其中Touch的第一个状态是 ACTION_DOWN, 表示按下了屏幕。之后,touch将会有后续事件,比如移动、抬起等,一个Action_DOWN, n个ACTION_MOVE, 1个ACTION_UP,就构成了Android中众多的事件。
- 按下(ACTION_DOWN) //表示用户按下了屏幕
- 移动(ACTION_MOVE) //表示用户在屏幕移动
- 抬起(ACTION_UP) //表示用户离开屏幕
- 取消手势(ACTION_CANCEL) //表示,不会由用户产生,而是由程序产生的
- 划出屏幕(ACTION_OUTSIDE)//表示滑出屏幕了
所有的操作事件首先必须执行的是按下操作(ACTIONDOWN),之后所有的操作都是以此作为前提,当按下操作完成后,接下来可能是一段移动(ACTIONMOVE)然后抬起(ACTION_UP),或者是按下操作执行完成后没有移动就直接抬起。因为所有的事件操作都发生在触摸屏上,而在屏幕上与用户交互的就是各种各样的视图组件(View),在Android中,所有的视图都继承于View,另外通过各种布局组件(ViewGroup)来对View进行布局,ViewGroup也继承于View。所有的UI控件例如Button、TextView都是继承于View,而所有的布局控件例如RelativeLayout、容器控件例如ListView都是继承于ViewGroup。所以,事件操作主要就是发生在View和ViewGroup之间,那么View和ViewGroup中主要有哪些方法来对这些事件进行响应呢?有如下3个方法: 1、public boolean dispatchTouchEvent(MotionEvent event)
2、 public boolean onTouchEvent(MotionEvent event)
3、 public boolean onInterceptTouchEvent(MotionEvent event)
在View和ViewGroup中都存在dispatchTouchEvent和onTouchEvent方法,特别的,在ViewGroup中还有一个onInterceptTouchEvent方法。这些方法的返回值全部都是boolean型,都返回true或者是false,这是因为事件传递的过程就是一个接一个,某一个点后根据方法boolean的返回值判断是否要继续往下传递。在Android中,所有的事件都是从开始经过传递到完成事件的消费,这些方法的返回值就决定了某一事件是否是继续往下传,还是被拦截了,或是被消费了。 接下来就是这些方法的参数,都接受了一个MotionEvent类型的参数,MotionEvent继承于InputEvent,用于标记各种动作事件。之前提到的ACTIONDOWN、ACTIONMOVE、ACTION_UP、ACTION_CANCEL都是MotinEvent中定义的常量。我们通过MotionEvent传进来的事件类型来判断接收的是哪一种类型的事件。到现在,这三个方法的返回值和参数你应该都明白了,接下来就解释一下这三个方法分别在什么时候处理事件。
- dispatchTouchEvent方法用于事件的分发,Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件没有被消费。返回false则继续往下分发,如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件。
- onInterceptTouchEvent是ViewGroup中才有的方法,View中没有,它的作用是负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在Android中View中是不能再包含子View的。
- onTouchEvent方法用于事件的处理,返回true表示消费处理当前事件,返回false则不处理,交给子控件进行继续分发。Android中事件的构成以及事件处理方法的基本概念介绍到这,接下来就通过一系列的测试来验证以及梳理总结。
- package com.example.toucheventdemo;
- import android.os.Bundle;
- import android.app.Activity;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.View.OnTouchListener;
- public class MainActivity extends Activity
- private CustomButton mButton_top;
- @Override
- protected void onCreate(Bundle savedInstanceState)
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mButton_top = (CustomButton) this.findViewById(R.id.cusbutton_top);
- mButton_top.setOnClickListener(this);
- mButton_top.setOnTouchListener(this);
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev)
- switch (ev.getAction())
- case MotionEvent.ACTION_DOWN:
- System.out.println("MainActivity--dispatchTouchEvent:"
- + "---MotionEvent.ACTION_DOWN---");
- break;
- case MotionEvent.ACTION_MOVE:
- System.out.println("MainActivity--dispatchTouchEvent:"
- + "---MotionEvent.ACTION_MOVE---");
- break;
- case MotionEvent.ACTION_UP:
- System.out.println("MainActivity--dispatchTouchEvent:"
- + "---MotionEvent.ACTION_UP---");
- break;
- default:
- break;
- return super.dispatchTouchEvent(ev);
- @Override
- public boolean onTouchEvent(MotionEvent event)
- switch (event.getAction())
- case MotionEvent.ACTION_DOWN:
- System.out.println("MainActivity--onTouchEvent:"
- + "---MotionEvent.ACTION_DOWN---");
- break;
- case MotionEvent.ACTION_MOVE:
- System.out.println("MainActivity--onTouchEvent:"
- + "---MotionEvent.ACTION_MOVE---");
- break;
- case MotionEvent.ACTION_UP:
- System.out.println("MainActivity--onTouchEvent:"
- + "---MotionEvent.ACTION_UP---");
- break;
- default:
- break;
- return super.onTouchEvent(event);
- /**
- * Called to process touch screen events. You can override this to
- * intercept all touch screen events before they are dispatched to the
- * window. Be sure to call this implementation for touch screen events
- * that should be handled normally.
- *
- * @param ev The touch screen event.
- *
- * @return boolean Return true if this event was consumed.
- */
- public boolean dispatchTouchEvent(MotionEvent ev)
- if (ev.getAction() == MotionEvent.ACTION_DOWN)
- onUserInteraction();
- if (getWindow().superDispatchTouchEvent(ev))
- return true;
- return onTouchEvent(ev);
[html] view plain copy
- public void onUserInteraction()
Activity.java [html] view plain copy
- /**
- * Used by custom windows, such as Dialog, to pass the touch screen event
- * further down the view hierarchy. Application developers should
- * not need to implement or call this.
- *
- */
- public abstract boolean superDispatchTouchEvent(MotionEvent event);
可以看到,触屏消息已经不会传递到OnTouchEvent(MotionEvent event)方法里面了,因为 dispatchTouchEvent方法返回 true,说明消息不会继续分发到onTouchEvent()方法 。然后在这个两个方法的返回之前加入输出,也就是把父类方法的返回值打印出来, [html] view plain copy
- System.out.println( "super.dispatchTouchEvent(ev):"+ super.dispatchTouchEvent(ev)+"" );
这说明默认情况下,如果消息没有被消费(处理),会返回false,接着事件会向下传递。如果最后也没有被处理消费,消息会向上返回回去,直到完成一个传递的过程。
2、加入显示控件情况 自定义一个Button:CustomButton,代码如下: [html] view plain copy