在Android触摸屏的过程中,有三个重要的方法,dispatchTouchEvent(事件分发)、onInterceptTouchEvent(事件拦截)、onTouchEvent(事件处理、消费)。
View、ViewGroup、Activity中都有dispatchTouchEvent,onTouchEvent方法;但是onInterceptTouchEvent只有ViewGroup中有。
触摸事件处理的原理请看http://blog.csdn.net/xyz_lmn/article/details/12517911,图文的方式讲解的很清楚。
我在此只是记录下,用代码进行的验证过程以及一些要点。
代码如下:
public class MyRelativeLayout extends RelativeLayout { public MyRelativeLayout(Context context) { super(context); } public MyRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) {
Log.e("Demo", "RelativeLayout --> onTouchEvent"+event.getAction()); return super.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("Demo", "RelativeLayout --> dispatchTouchEvent"+ev.getAction()); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); }
}
public class MyButton extends Button { public MyButton(Context context) { super(context); } public MyButton(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { //触摸 Log.e("Demo", "Button --> onTouchEvent" + event.getAction() + ""); return super.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent event) { //事件分发 Log.e("Demo", "Button --> dispatchTouchEvent" + event.getAction() + ""); return super.dispatchTouchEvent(event); }
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener, View.OnTouchListener { private RelativeLayout m_rlayout; private MyButton m_button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_main); m_rlayout = (RelativeLayout) findViewById(R.id.relative_layout); m_button = (MyButton) findViewById(R.id.button); m_rlayout.setOnTouchListener(this); m_button.setOnTouchListener(this); m_button.setOnClickListener(this); m_rlayout.setOnClickListener(this); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); } @Override public void onClick(View v) {
Log.e("Demo", "点击事件" + "onClick"+v); } @Override public boolean onTouch(View v, MotionEvent event) {
Log.e("Demo", "触摸事件" + "onTouch"+v); return false; }
}
<?xml version="1.0" encoding="utf-8"?><com.example.myinflatedemo.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/relative_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.myinflatedemo.MyButton android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮" /></com.example.myinflatedemo.MyRelativeLayout>
这些代码很简单,入门了的人都看得懂。
下面是我验证的几个要点:
1、onTouchEvent 返回ture代表消费了此事件,不再传递给上层的GroupView(默认返回false)。
2、dispatchTouchEvent 返回true(Action_Down),后续事件(Action_move、up)都不会传递过来(默认是返回false)。
3、onInterceptTouchEvent 返回true(Action_Down),拦截事件,此事件不会分发到childView中(默认返回false)。
将MyRelativeLayout的dispatchTouchEvent方法的返回值设为true。
@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) { super.onInterceptTouchEvent(ev); return true;}
运行结果:
Logcat中没有出现Button相关的日志,整个流程是ACTION_DOWN dispatchTouchEvent --> ACTION_DOWN onTouchEvent --> ACTION_UP dispatchTouchEvent --> ACTION_UP onTouchEvent。
4、如果所有的view、或者viewgroup都没有消费onTouchEvent事件(Action_Down),后续的事件都不会再被传递(Action_move、up)。
将MyButton和MyRelativeLayout中的onTouchEvent方法的返回值都改成false
@Overridepublic boolean onTouchEvent(MotionEvent event) { //触摸 Log.e("Demo", "Button --> onTouchEvent" + event.getAction() + ""); super.onTouchEvent(event); return false;}
运行结果如下:
RelativeLayout和Button都执行了onTouchEvent,处理的事件只有0(Action_down)。