android点击事件分发,Android 事件分发

1、事件分发机制

用户点击产生一个MotionEvent,系统把这个事件分发给具体的view消费

2、MotionEvent介绍

手势接触屏幕产生的事件

MotionEvent对象操作有:

1、MotionEvent.ACTION_DOWN   手势按下,是所有触发操作中最开始的动作

2、MotionEvent.ACTION_UP 手势向上,是所有触发操作最后的动作

3、MotionEvent.ACTION_MOVE 手势按下后没有收回

4、MotionEvent.ACTION_CANCEL  事件结束 理论上是ACTION_UP 后执行,但也有可能是非人为因素导致的.

3e62fb448876d68b3a4760ff74312da6.png

3、事件分发的本质

将MotinEvent传递到某个具体的view处理的过程

4、事件分发的对象及分发顺序

Activity ViewGroup View

8c1900948c8cf8271633c92044048d29.png

Activity: 控制生命周期、处理事件

统筹视图的现实和添加、通过其它回调方法与Window、View交互.

View:所有UI组件的基类

ViewGroup:一组view的组合,其本身也是view的子类,是android布局的所有父类.比view多了可包含子view和定义布局参数的功能.

5、事件分发的过程协助者

协助者:dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()

dispatchTouchEvent():用来进行事件的分发,当点击事件能够传递给当前view,该方法就会被调用.返回结果受到当前View的TouchEvent和下级view的dispatchTouchEvent方法影响,表示是否消费当前的事件

onTouchEvent:在dispatchTouchEvent方法内部调用,用来处理事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前view无法再接受到后续的事件队列。而且onTouchEvent返回值由clickable和longclickable共同决定

onInterceptTouchEvent():在dispatchTouchEvent()内部调用.用来表示是否拦截当前的事件.如果当前view拦截了某个事件,那么在同一个事件序列当中,此方法不会被调用,返回结果表示是否拦截当前事件。

6、代码说明演示

ViewGroup 代表 -》新建类DemoLayout 继承LinearLayout

public class DemoLayout extends LinearLayout {

private static final String TAG = "DemoLayout";

public DemoLayout(Context context) {

super(context);

}

public DemoLayout(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

}

public DemoLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

public DemoLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

}

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

// 父容器的分发事件

Log.i(TAG, "----父容器的分发事件"+ev.getAction());

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

break;

case MotionEvent.ACTION_UP:

break;

case MotionEvent.ACTION_CANCEL:

break;

}

return super.dispatchTouchEvent(ev);

}

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

//父容器的拦截事件

Log.i(TAG, "----父容器的拦截事件"+ev.getAction());

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

break;

case MotionEvent.ACTION_UP:

break;

case MotionEvent.ACTION_CANCEL:

break;

}

return super.onInterceptTouchEvent(ev);

}

@Override

public boolean onTouchEvent(MotionEvent ev) {

//父容器的触摸事件

Log.i(TAG, "----父容器的触摸事件"+ev.getAction());

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

break;

case MotionEvent.ACTION_UP:

break;

case MotionEvent.ACTION_CANCEL:

break;

}

return super.onTouchEvent(ev);

}

}

View 代表-》 新建类View集成Button

public class View extends android.support.v7.widget.AppCompatButton {

private static final String TAG = "View";

public View(Context context) {

super(context);

}

public View(Context context, AttributeSet attrs) {

super(context, attrs);

}

public View(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

@Override

public boolean dispatchTouchEvent(MotionEvent event) {

Log.i(TAG, "----子容器的分发事件"+ event.getAction());

return super.dispatchTouchEvent(event);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

Log.i(TAG, "----子容器的触摸事件"+event.getAction());

return super.onTouchEvent(event);

}

}

操作准备:在layout布局中创建DemoLayout布局,包含View控件

android:layout_width="500dp"

android:layout_height="500dp"

android:clickable="true"

android:background="#000000">

android:id="@+id/view_touch"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:text="事件分发"/>

初次运行看下运行流程:

没有拦截时

481ba690de78e471a870787f2165d194.png

父容器把事件交给了子容器处理 dispatchTouchEvent进行事件分发 onInterceptTouchEvent没有拦截 子容器执行dispatchTouchEvent事件分发,再执行onTouchEvent事件

拦截后 代码和流程

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

//父容器的拦截事件

Log.i(TAG, "----父容器的拦截事件"+ev.getAction());

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

break;

case MotionEvent.ACTION_UP:

break;

case MotionEvent.ACTION_CANCEL:

break;

}

return true;

}

220930658daf7bd47006340937bc09ac.png

DemoLayout  dispatchTouchEvent进行事件分发 onInterceptTouchEvent拦截  父容器执行onTouchEvent,(备注:父容器clickable默认值是false即代表onTouchEvent 返回false,后续操作系列Action_UP不会执行,如下图,所以在xml中要声明clickable="true").从上看出拦截事件onIntercepeTpuchEvent不会再执行,只会被消费一次

5d9adb9ea7b830ae5da57d00c9a0ced6.png

若子容器不消费onTouchEvent,则事件会传递给父容器,而且不会接受后续操作,父容器onInterceptTouchEvent也不会再执行.同样若子容器在xml声明clickable="false"也就代表着子容器的onTouchEvent返回false。(备注操作:事件系列操作指的是按下ACTION_DOWN、移动ACTION_MOVE、抬起ACTION_UP,所谓后续操作如图子容器的ACTION_UP就没有再执行了)

@Override

public boolean onTouchEvent(MotionEvent event) {

Log.i(TAG, "----子容器的触摸事件"+event.getAction());

return false;

}

d4583178dcdf15d176fbf99c353fdb60.png

若子容器的onTouchEvent返回false,onClick方法也是不能够执行的,因为回调方法onClick()是在onTouchEvent中执行的

总结

bbc8c5f79290099a7ebf7ece631ec017.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值