事件分发小结

Android开发中,事件分发是非常重要的,了解熟悉整个事件分发过程有助于更好的分析各种点击滑动失效问题,也是一个安卓开发必会的一部分,但是时间长了,对整个流程多少会有些模糊,所以在此记录一下

网上看到一张图,可以很详细的描述整个事件分发的过程

事件分发流程图

原文的链接

  • 问题一:

当ViewGroup重写的onInterceptTouchEvent,并且始终返回了true,那么子view就永远无法接受到了事件

但是在实际开发中可能会有这种需求,在按下(ACTION_DOWN)的时候,需要子view进行时间反馈,但在滑动(ACTION_MOVE)或者抬起(ACTION_UP)的时候需要父布局进行拦截操作,这个时候可以使用requestDisallInterceptRouchEvent(boolean disallowIntercept),该方法在子view中调用getParent().requestDisallInterceptRouchEvent(true)请求父布局禁用拦截事件功能

相关资料

具体例子,在我做的项目中,在viewpager中的每一页fragment中都折线图,viewpager是可以左右切换的,每一页的fragment中的折线图也是可以手势缩放的,所以这就和viewpager滑动有冲突,利用requestDisallInterceptRouchEvent,我们可以自定义折线图控件继承项目中使用的(项目中使用的mpandroid),重写onTouchEvent,当水平滑动的时候,getParent().requestDisallInterceptRouchEvent(true),请求父布局不拦截事件,交给子view处理。

相关源码如下:

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
40
41
42
43
44
45
46
47
48
49
package com.nongfaziran.workiot.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.github.mikephil.charting.charts.LineChart;

/**
* Created by fengan on 2018/2/3.
* email:fengan1102@gmail.com
* 解决折线图在viewpager滑动冲突
*/

public class LineChartInViewPager extends LineChart {

PointF downPoint = new PointF();

public LineChartInViewPager(Context context) {
super(context);
}

public LineChartInViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}

public LineChartInViewPager(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent evt) {
switch (evt.getAction()) {
case MotionEvent.ACTION_DOWN:
downPoint.x = evt.getX();
downPoint.y = evt.getY();
break;
case MotionEvent.ACTION_MOVE:
if (getScaleX() > 1 && Math.abs(evt.getX() - downPoint.x) > 5) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
}
return super.onTouchEvent(evt);
}
}

栗子

之前在B站做了几个月,其中有一个需求,就是父view要知道用户点击的具体坐标用于上报,并且还不影响子view各自的点击事件,可以参考一下我的好基友的做法

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
* Create by zhangtietou on 18-2-5 下午9:19
* Copyright (c) 2018. All rights reserved
*
* Last modified 18-2-5 下午9:19
*/

package com.bilibili.ad.adview.common;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.bilibili.magicasakura.widgets.TintFrameLayout;

/**
* Created by zhangtietou on 2018/2/5.
*
* @since Version
*/

public class AdTintFrameLayout extends TintFrameLayout {
int currentDownX = -999;
int currentDownY = -999;
int currentUpX = -999;
int currentUpY = -999;
int width = -999;
int height = -999;

public AdTintFrameLayout(Context context) {
super(context);
}

public AdTintFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}

public AdTintFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
currentDownX = (int) event.getX();
currentDownY = (int) event.getY();
case MotionEvent.ACTION_UP:
currentUpX = (int) event.getX();
currentUpY = (int) event.getY();
default:
break;
}
width = getWidth();
height = getHeight();
return super.onInterceptTouchEvent(event);
}

public int getCurrentDownX() {
return currentDownX;
}

public int getCurrentDownY() {
return currentDownY;
}

public int getCurrentUpX() {
return currentUpX;
}

public int getCurrentUpY() {
return currentUpY;
}

public int getCurrentWidth() {
return width;
}

public int getCurrentHeight() {
return height;
}
}

未完待续

文章目录