Android触摸事件分发与响应

来源:互联网 发布:服务器开启8080端口 编辑:程序博客网 时间:2024/06/10 05:47

了解Android控件的触摸事件传递与处理对我们日常开发中自定义控件和触摸事件冲突解决有重大意义。Android控件的触摸事件传递和处理主要有以下几个方法,下面一一介绍。

一、与触摸事件有关的几个方法

boolean dispatchTouchEvent(MotionEvent ev); 接收到触摸事件时,是否分发事件到下面的View
返回true:分发触摸事件
返回false:不分发,下面的View就拿不到触摸事件boolean onInterceptTouchEvent(MotionEvent ev);接收到触摸事件时,是否拦截事件
返回true:拦截,则调用onTouchEvent方法处理事件
返回false:不拦截,事件继续往子View传boolean onTouchEvent(MotionEvent ev);是否响应事件
返回true:响应
返回false:不响应boolean onTouch(View v, MotionEvent event);是否响应事件,当View调用了setOnTouchListener方法设置了触摸监听器,则事件响应的时候先调用onTouch方法
返回true:响应,则onTouchEvent方法不执行
返回false:不响应,并调用onTouchEvent方法void requestDisallowInterceptTouchEvent(boolean disallowIntercept); 请求父控件是否不拦截事件
返回true:不允许父控件的onInterceptTouchEvent调用
返回false:允许调用


二、拥有这些方法的类

父类子类拥有的方法ActivityActivitydispatchTouchEvent、onTouchEvent
ViewGroupRelativeLayout, LinearLayout...dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent、requestDisallowInterceptTouchEventViewButton、TextView...dispatchTouchEvent、onTouchEvent


三、事件处理规则

触摸事件是从Activity分发(只是分发,还没有处理)到父控件,父控件先判断是否拦截,如果不拦截事件,则继续分发到子控件,然后一直往下分发。但处理就刚好相反,由子控件先处理事件,如果子控件没有处理事件,则交给到父控件处理,一直往上处理,直到哪个控件处理了触摸事件,就事件处理就到此结束。

1.当用户触摸屏幕的时候,从按下到移动,最后到抬起,会依次产生ACTION_DOWN、ACTION_MOVE、ACTION_UP三种触摸事件,事件先传到Activity,然后Activity调用分发事件方法dispatchTouchEvent,如果返回true,则事件就会传给Activity的第一个父控件。

2.父控件拿到事件之后,也会调用分发事件方法dispatchTouchEvent,如果返回true,则继续调用拦截方法onInterceptTouchEvent,如果返回true,则父控件拦截了事件,并调用父控件的onTouchEvent方法,下面的子控件就不会再响应onTouchEvent,onTouch的方法。

3.子控件拿到事件之后,先判断是否设置了OnTouchListener, 如果设置了,则调用OnTouchListener的onTouch方法,如果返回true,事件已经处理到此结束,则跳过onTouchEvent方法,否则调用onTouchEvent方法,当onTouchEvent方法返回true,则事件处理到此结束,上面的父控件就不会再调用onTouchEvent方法。

4.如果某一个控件响应了ACTION_DOWN事件,则后续的ACTION_MOVE、ACTION_UP事件就会直接交给该控件处理,除非它的父控件拦截了后续的事件,但可以在处理ACTION_DOWN事件时,调用requestDisallowInterceptTouchEvent禁止父控件的拦截。如果控件没有处理ACTION_DOWN事件,则后续的事件就不会再传到该控件中,当下一次的ACTION_DOWN事件产生时,还是会传给该View的。


四、下面来做一个演示

定义MainActivity、ParentView、ChildView,OnTouchListener

MainActivity——>妈妈

ParentView——>爸爸

ChildView——>我

OnTouchListener——>老婆

Event——>苹果(一次来三个苹果,模拟ACITON_DWON、ACTION_MOVE、ACTION_UP事件)

用一家人吃苹果这个案例,模拟触摸事件的处理。


妈妈MainActivity源码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
packagecom.test.activity;
 
importcom.example.javawebtest.R;
 
importandroid.os.Bundle;
importandroid.util.Log;
importandroid.view.MotionEvent;
importandroid.app.Activity;
 
publicclass MainActivity extendsActivity {
 
    @Override
    protectedvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    @Override
    publicboolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        booleaneat = false;
        Log.i(getClass().getSimpleName(),"妈妈"+ (eat ? "吃了苹果": "没有吃,扔了"));
        returneat;
    }
     
    @Override
    publicboolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        Log.i(getClass().getSimpleName(),"妈妈想分给爸爸苹果");
        returnsuper.dispatchTouchEvent(ev);
    }
 
}


爸爸ParentView的源码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
packagecom.test.view;
 
importandroid.content.Context;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.MotionEvent;
importandroid.widget.RelativeLayout;
 
publicclass ParentView extendsRelativeLayout {
 
    publicParentView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }
     
    @Override
    publicboolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        Log.i(getClass().getSimpleName(),"爸爸想分给我苹果");
        returnsuper.dispatchTouchEvent(ev);
    }
     
    @Override
    publicboolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        booleanintercept = false;
        Log.i(getClass().getSimpleName(),"爸爸"+ (intercept ? "想吃": "不想吃") + "苹果");
        returnintercept ? true: super.onInterceptTouchEvent(ev);
    }
     
    @Override
    publicboolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        booleaneat = false;
        Log.i(getClass().getSimpleName(),"爸爸"+ (eat ? "吃了苹果": "没有吃,给了妈妈"));
        returneat;
    }
 
}

我ChildView、老婆OnTouchListener的源码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
packagecom.test.view;
 
importandroid.content.Context;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.MotionEvent;
importandroid.view.View;
importandroid.view.View.OnTouchListener;
 
publicclass ChildView extendsView implementsOnTouchListener {
 
    publicChildView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        setOnTouchListener(this);
    }
 
    @Override
    publicboolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        booleaneat = false;
        Log.i(getClass().getSimpleName(),"我"+ (eat ? "吃了苹果": "没有吃苹果,给了爸爸"));
        returneat;
    }
 
    @Override
    publicboolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        booleaneat = false;
        Log.i(getClass().getSimpleName(),"老婆"+ (eat ? "吃了苹果": "没有吃苹果,给了我"));
        returneat;
    }
     
}


场景一:大家谁也没吃苹果,效果如下图

\

刚开始,第一个苹果一直往下传,谁也没吃,后面妈妈知道我们都不喜欢吃苹果,第二、第三个苹果都没有传给我们,就扔了...


<喎�"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+IAogs6G+sLb+o7rO0rPUwcvGu7n7o6y9q0NoaWxkVmlld7XEb25Ub3VjaEV2ZW50tcRlYXTWw86qdHJ1ZTwvcD4KPHA+PGltZyBzcmM9"http://www.2cto.com/uploadfile/Collfiles/20141221/2014122109040324.png" alt="\">

我吃了苹果,不过每次吃之前都要询问老婆,要是老婆吃了,我就不能吃...


场景三:爸爸抢了苹果,将onInterceptTouchEvent的intercept置为true


结果苹果被老爸吃了,然后再没有我的事情了...

0 0
原创粉丝点击