android事件分发和案例

来源:互联网 发布:小米windows平板3 编辑:程序博客网 时间:2024/06/01 12:51

1、事件分发

android控件层次嵌套关系(平级嵌套,父子嵌套)的视图关系,也就产生view(viewgroup)对触摸或者点击事件的消费关系,每一个控件都可以消费或者拒绝消费事件,在嵌套的布局中,关系可能更复杂些。android中的事件分发机制,保证我们想要的view获取到相应的事件。
view和viewgroup本质是做为view,但对于事件分发机制还是有很多区别,viewgroup可以做为view的载体,事件可能更复杂些。

1、ViewGroup中的分发机制三个方法

public boolean dispatchTouchEvent(MotionEvent ev);    public boolean onInterceptTouchEvent(MotionEvent ev);    public boolean onTouchEvent(MotionEvent ev);  

2、View中的分发机制两个方法

public boolean dispatchTouchEvent(MotionEvent ev);    public boolean onTouchEvent(MotionEvent ev);

3、Activity的回调方法

public boolean dispatchTouchEvent(MotionEvent ev);    public boolean onTouchEvent(MotionEvent ev);  

3、ViewGroup和View的事件分发

当我们触摸到Activity中的控件时,分发流程如下

ViewGroup里的onInterceptTouchEvent默认值是false这样才能把事件传给View里的onTouchEvent.ViewGroup里的onTouchEvent默认值是falseView里的onTouchEvent返回默认值是true.这样才能执行多次touch事件。

这里写图片描述

1、事件分发dispatchTouchEvent()

举例:LinearLayout
当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由 dispatchTouchEvent 方法进行分发,

如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的

interceptTouchEvent 方法来决定是否要拦截这个事件,

如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。
在ViewGroup中

 public boolean dispatchTouchEvent(MotionEvent ev){        ....//其他处理,在此不管        View[] views=getChildView();        for(int i=0;i<views.length;i++){           //判断下Touch到屏幕上的点在该子View上面             if(...){            if(views[i].dispatchTouchEvent(ev))              return true;             }        }        ...//其他处理,在此不管    }

在View中

   public boolean dispatchTouchEvent(MotionEvent ev){        ....//其他处理,在此不管        return onTouchEvent(event);    }

2、事件处理onInterceptTouchEvent()

决定touch事件是否向下处理
1、如果onInterceptTouchEvent()返回true,代表当前ViewGroup消费了事件,不再向下传递touch事件 。因此事件会被当前控件的onTouchEvent()处理
2、如果onInterceptTouchEvent()返回false,代表当前ViewGroup没有处理事件,处理向下传递给子view(或者子viewgroup),这样touch事件又到子view的onInterceptTouchEvent()。

LinearLayoutonInterceptTouchEvent默认值是false这样才能把事件传给View里的onTouchEvent.

3、事件处理onTouchEvent()

onTouchEvent()用于处理事件(重点onTouch这个事件是从子控件回传到父控件的,一层层向下传),返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递。返回false,则向上传递给父控件,详细一点就是这个touch事件就给了父控件,那么后面的up事件就是到这里touch触发,不会在传给它的子控件。如果父控件依然是false,那touch的处理就给到父控件的父控件,那么up的事件处理都在父控件的父控件,不会触发下面的。

ViewGroup里的onTouchEvent默认值是falseView里的onTouchEvent返回默认值是true.这样才能执行多次touch事件。

4、关于ViewGroup和View源码

ViewGroup中
1、在ViewGroup中dispatchTouchEvent()中默认返回false
2、dispatchTouchEvent()中返回false后,进入到onInterceptTouchEvent()方法中,默认返回false

 public boolean onInterceptTouchEvent(MotionEvent ev) {        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)                && ev.getAction() == MotionEvent.ACTION_DOWN                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)                && isOnScrollbarThumb(ev.getX(), ev.getY())) {            return true;        }        return false;    }

3、这样事件最终才传递给子vew的onTouchEvent()方法中。也就是定义的Linearlayout中的点击事件可以向下TextView,Button中传递

在View中
onTouchEvent默认返回true
也就是最终TextView,Button最终能够响应点击事件。

5、案例分析

当点击红包区域时,红包区域响应事件,点击外部蓝色时,外部响应
这里写图片描述

点击红包区域时,响应事件,外层不响应
外部区域:

package com.example.touchdemo;import android.content.Context;import android.graphics.Canvas;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;/** * Created by yuxiaogang on 2017/4/5. */public class MyLinearLayout extends LinearLayout {    public MyLinearLayout(Context context) {        super(context);    }    public MyLinearLayout(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        Log.i("------ll outer", "***dispatchTouchEvent--start ");        boolean b = super.dispatchTouchEvent(ev);        Log.i("------ll outer", "***dispatchTouchEvent--end "+b);        return true;    }}

内部区域代码

package com.example.touchdemo;import android.content.Context;import android.graphics.Canvas;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;/** * Created by yuxiaogang on 2017/4/5. */public class MyLinearLayoutInner extends LinearLayout {    public MyLinearLayoutInner(Context context) {        super(context);    }    public MyLinearLayoutInner(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        Log.i("------ll inner", "***dispatchTouchEvent--start ");        boolean b = super.dispatchTouchEvent(ev);        Log.i("------ll inner", "***dispatchTouchEvent--start "+b);        return true;    }}

参考博客
http://blog.csdn.net/xyz_lmn/article/details/12517911

0 0
原创粉丝点击