To the once unbridgeable chasm ---- The king has arrived


Let’s make a few points clear at the beginning
1. There are three things that are very long and similar. They are dazzling and disturbing. | - distribute dispatchTouchEvent = d16t | - truncated onInterceptTouchEvent = o19t onTouchEvent = o10t 2 | - consumption. Event distribution mechanism of participants with their own callback methods: | - gray Activity: o10t d16t | - purple ViewGroup: o10t d16t o19t | - orange monomer View: O10t d16t 3. Several kinds of common MotionEvent time | - MotionEvent. ACTION_DOWN = 0; Press | - MotionEvent. ACTION_UP = 1; Lift the | - MotionEvent. ACTION_MOVE = 2; Mobile | - MotionEvent. ACTION_CANCEL = 3; cancelCopy the code

I’ll give you the legend here, just to get a sense of it
The following indicates: The contact is on the Activity, The press event (0) triggers D16T (dispatchTouchEvent) and the press event (0) triggers O10T (onTouchEvent) and the raise event (1) triggers D16T (dispatchTouchEvent) Then the raise event (i.e. 1) triggers o10T (i.e. OnTouchEvent) -- which I think is the best way to describe itCopy the code


1. Event transmission under normal circumstances

0. Customize two test views

The layout tree is as follows: Now customize a single View and a ViewGroup

/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2019/2/21/021:9:11<br/> * Email: [email protected]<br/> * Description: Public class EventActivity extends AppCompatActivity {private static final String TAG = "EventTest"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_event_test); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "OnTouchEvent :--" + event.getaction () +" -- Swastika Swastika swastika); return super.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.e(TAG, "DispatchTouchEvent :--" + ev.getAction() + "-- Swastika Swastika swastika); return super.dispatchTouchEvent(ev); } /** * Author: Zhang Fengjie Teilie <br/> * Time: 2019/2/21/021:9:06<br/> * Email: [email protected]<br/> * Description: Public class SonView extends View {private static final String TAG = "EventTest"; public SonView(Context context) { super(context); } public SonView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); setBackgroundColor(0xffE58F46); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.e(TAG, "SonView - dispatchTouchEvent:" + event. GetAction () + "-- † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † †"); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "SonView -- onTouchEvent: --" + event. GetAction () + "-- † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † †"); return super.onTouchEvent(event); } /** * Author: Zhang Fengjie Teilie <br/> * Time: 2019/2/21/021:9:06<br/> * Email: [email protected]<br/> * Description: Public class FatherViewGroup extends FrameLayout {private static final String TAG = "EventTest"; public FatherViewGroup(Context context) { super(context); } public FatherViewGroup(Context context, AttributeSet attrs) { super(context, attrs); setBackgroundColor(0xff9869B7); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.e(TAG, "FatherViewGroup -- dispatchTouchEvent: --" + ev. GetAction () + "-- ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e(TAG, "FatherViewGroup -- onInterceptTouchEvent: --" + ev. GetAction () + "-- ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯"); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "FatherViewGroup -- onTouchEvent: --" + event. GetAction () + "-- ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯"); return super.onTouchEvent(event); }}Copy the code

1. Click from outside the two views

I did it in the legend section, but I don’t want to talk about it

--0-- Swastika Swastika OnTouchEvent :--0 -- Swastika swastika For example, when you have a swastika, you have a swastika. When you have a Swastika, you have a swastikaCopy the code

2. Click the purple ViewGroup

At the d16T of the Activity, after that, the event goes to the ViewGroup

--0-- Swastika Swastika FatherViewGroup - dispatchTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 10:36:34. 2019-02-21, 040: FatherViewGroup - onInterceptTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 10:36:34. 2019-02-21, 041: FatherViewGroup -- onTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 10:36:34. 2019-02-21, 041: OnTouchEvent :--0 -- Swastika swastika For example, when a swastika was born, a swastika was born, and a swastika was bornCopy the code

3. Click the orange View unit

At o18T of the ViewGroup, after that, the event goes to the View,

It feels like… A chain. What happens if one of them breaks?

--0-- Swastika Swastika FatherViewGroup - dispatchTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 10:46:15. 2019-02-21, 722: FatherViewGroup - onInterceptTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 10:46:15. 2019-02-21, 722: SonView - dispatchTouchEvent: 0 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † 10:46:15. 2019-02-21, 723: SonView -- onTouchEvent: - 0 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † 10:46:15. 2019-02-21, 724: FatherViewGroup -- onTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 10:46:15. 2019-02-21, 726: OnTouchEvent :--0 -- Swastika swastika For the first time in the history of the United States, a swastika has become an important part of the world's history. For the first time in the history of the United States, a swastika has become an important part of our historyCopy the code

Two, the chain test

1.d16tnamelydispatchTouchEvent :

Slogan: better die when life is a disgrace, I can’t get, you also don’t want to get!


1.1. The Activityd16tDiscontinued:It is better to die when life is a disgrace

Activity: I’m sorry, I can’t play the event! D16t returns false. Throw the event away

When this chain breaks… Even if you click on the View unit, the event will not pass.

---->[EventActivity#dispatchTouchEvent]------------------------------ @Override public boolean DispatchTouchEvent (MotionEvent ev) {log.e (TAG, "dispatchTouchEvent:--" + ev.getaction () + "-- swastika swastika swastika swastika); return false; } 11:01:19 2019-02-21. 109. 29054-29054 / com toly1994. Analyzer E/EventTest: DispatchTouchEvent: - 0 - swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika 11:01:19. 2019-02-21, 159, 29054-29054 / com. Toly1994. Analyzer E/EventTest: DispatchTouchEvent :--1-- Swastika swastikaCopy the code

1.2. The ViewGroupd16tOff the chain

Now back to the original situation, the Activity gives the event to the ViewGroup to play with, and the ViewGroup says: I’m not happy either! Then a throw

The Activity’s o10T is called back after the ViewGroup’s D16t returns false

---->[FatherViewGroup#dispatchTouchEvent]-------------------- @Override public boolean dispatchTouchEvent(MotionEvent The event) {Log. E (TAG, "FatherViewGroup -- dispatchTouchEvent: --" + ev. GetAction () + "-- ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯"); return false; } -- 02-21 11:27:07.487: dispatchTouchEvent:--0-- swastika FatherViewGroup - dispatchTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 11:27:07. 2019-02-21, 489: OnTouchEvent :--0 -- Swastika swastika For example, when you get to the end of your life, you get to the end of your life, and you get to the end of your lifeCopy the code

1.3. The View of monomerd16tOff the chain

Now let’s go back to the original case

---->[SonView#dispatchTouchEvent]-------------------- @Override public boolean dispatchTouchEvent(MotionEvent event) { The e (TAG, "SonView - dispatchTouchEvent:" + event. GetAction () + "-- † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † †"); return false; } 2019-02-21 11:28:32.080: dispatchTouchEvent:--0-- swastika swastika FatherViewGroup - dispatchTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 11:28:32. 2019-02-21, 081: FatherViewGroup - onInterceptTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 11:28:32. 2019-02-21, 081: SonView - dispatchTouchEvent: 0 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † 11:28:32. 2019-02-21, 082: FatherViewGroup -- onTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 11:28:32. 2019-02-21, 083: OnTouchEvent :--0 -- Swastika swastika For example, when a swastika was born, a swastika was born, and a swastika was bornCopy the code
1.4 To summarized16t

Conclusions from the tests:

So what dispatchTouchEvent does is it distributes the event, it's not going anywhere, it's not going anywhere, it's not going anywhere, it's going to trigger the o10T, rightCopy the code

2.o18tImpact on events

The onInterceptTouchEvent method, which is unique to the ViewGroup, determines whether the event is interrupted

---->[FatherViewGroup#onInterceptTouchEvent]-------------------- @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e(TAG, "FatherViewGroup -- onInterceptTouchEvent: --" + ev. GetAction () + "-- ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯"); return true; --0-- Swastika swastika swastika FatherViewGroup - dispatchTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 11:54:46. 2019-02-21, 649: FatherViewGroup - onInterceptTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 11:54:46. 2019-02-21, 650: FatherViewGroup -- onTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 11:54:46. 2019-02-21, 652: OnTouchEvent :--0 -- Swastika Swastika For the first time in a century, a swastika and a swastika have become a part of the worldCopy the code

3.o10tOff the chain
3.1: When a ViewGroup consumes an event

By default, the event is consumed by the top level, so only when the ViewGroup consumes the event, the event is not passed down

---->[FatherViewGroup#onTouchEvent]-------------------- @Override public boolean onTouchEvent(MotionEvent event) { The e (TAG, "FatherViewGroup -- onTouchEvent: --" + event. GetAction () + "-- ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯"); return true; } 12:09:06 2019-02-21. 605. 11221-11221 / com toly1994. Analyzer E/EventTest: DispatchTouchEvent: - 0 - swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika 12:09:06. 2019-02-21, 606, 11221-11221 / com. Toly1994. Analyzer E/EventTest: FatherViewGroup - dispatchTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 12:09:06. 2019-02-21, 606, 11221-11221 / com. Toly1994. Analyzer  E/EventTest: FatherViewGroup - onInterceptTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 12:09:06. 2019-02-21 606 11221-11221/com.toly1994.analyzer E/EventTest: SonView - dispatchTouchEvent: 0 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † 12:09:06. 2019-02-21 607 11221-11221/com.toly1994.analyzer E/EventTest: SonView -- onTouchEvent: - 0 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † 12:09:06. 2019-02-21 607 11221-11221/com.toly1994.analyzer E/EventTest: FatherViewGroup -- onTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 12:09:06. 2019-02-21, 621, 11221-11221 / com. Toly1994. Analyzer E/EventTest: DispatchTouchEvent: - 1 - swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika swastika 12:09:06. 2019-02-21, 621, 11221-11221 / com. Toly1994. Analyzer E/EventTest: FatherViewGroup - dispatchTouchEvent: - 1 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 12:09:06. 2019-02-21, 622, 11221-11221 / com. Toly1994. Analyzer E/EventTest: FatherViewGroup -- onTouchEvent: - 1 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯Copy the code

3.2: When a child View consumes an event

---->[SonView#onTouchEvent]-------------------- @Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "SonView -- onTouchEvent: --" + event. GetAction () + "-- † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † †"); return true; --0-- Swastika, swastika, swastika FatherViewGroup - dispatchTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 12:10:05. 2019-02-21, 683: FatherViewGroup - onInterceptTouchEvent: - 0 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 12:10:05. 2019-02-21, 683: SonView - dispatchTouchEvent: 0 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † 12:10:05. 2019-02-21, 683: SonView -- onTouchEvent: - 0 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † 12:10:05. 2019-02-21, 724: DispatchTouchEvent :--1-- Swastika Swastika FatherViewGroup - dispatchTouchEvent: - 1 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 12:10:05. 2019-02-21, 724: FatherViewGroup - onInterceptTouchEvent: - 1 - ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ ☯ 12:10:05. 2019-02-21, 724: SonView - dispatchTouchEvent: 1 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † 12:10:05. 2019-02-21, 724: SonView -- onTouchEvent: - 1 - † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † † †Copy the code

3.3 Summaryo10t

Conclusions from the tests:

[d16t] and [o10t] will not be passed on to each other after the event has been consumed. The onTouchEvent will not be passed on to each other after the event has been consumed. I'll give you $100 a month for living expenses, this is called dispatchTouchEvent distribution, the cost of living is quite MotionEvent you (ViewGroup) : Get the 100 pieces, you can decide whether to give the 100 pieces to your son (View) as living expenses (dispatchTouchEvent) when you decide to give, but you can also interrupt the idea by onInterceptTouchEvent midway... | - son got the money, money is not the | - son get not to spend money, is confiscated by the old daddy, daddy took, money is no | - son get not to spend money, is confiscated by the old daddy, daddy didn't spend, and then was confiscated by the wife, the wife spent, the money did not have it is for this reason, almost by default are afraid to spend with your son, But the person behind had passed in the hand to have to spend, want to see a wife to give above all, do not give, behind did not play...Copy the code

If the above is clear, the use aspect should be no problem


Two, source view

1.Activity and ViewGroupdispatchTouchEvent

---->[Activity#dispatchTouchEvent]----------------------------
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
--->if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
--->return onTouchEvent(ev);
}

|---这里可以很清楚的看清Activity的onTouchEvent回调的时机即
    getWindow().superDispatchTouchEvent(ev)  返回false时触发
|---getWindow这里就不废话了,前面都说过,是PhoneWindow对象,直接进

---->[PhoneWindow#dispatchTouchEvent]----------------------------
|--- 调用的是mDecor的方法
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
    return mDecor.superDispatchTouchEvent(event);
}

---->[PhoneWindow$DecorView#superDispatchTouchEvent]----------------------------
|--- 这皮球踢得...mDecor是DecorView对象,继承自FrameLayout,在上一辈便是ViewGroup
|--- 所以这样看来,Activity的dispatchTouchEvent的本质也是ViewGroup触发的
public boolean superDispatchTouchEvent(MotionEvent event) {
    return super.dispatchTouchEvent(event);
}

---->[ViewGroup#superDispatchTouchEvent]----------------------------
|---这个方法大概100多行
/**
 * {@inheritDoc}
 */
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
        ...
--->    final boolean intercepted;//是否打断
        if (actionMasked == MotionEvent.ACTION_DOWN
                || mFirstTouchTarget != null) {
            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            if (!disallowIntercept) {
--->            intercepted = onInterceptTouchEvent(ev);//触发onInterceptTouchEvent,默认false
                ev.setAction(action); // restore action in case it was changed
            } else {
                intercepted = false;
            }
        } else {
            intercepted = true;
        }

        if (intercepted || mFirstTouchTarget != null) {
            ev.setTargetAccessibilityFocus(false);
        }

        // Check for cancelation.
        final boolean canceled = resetCancelNextUpFlag(this)
                || actionMasked == MotionEvent.ACTION_CANCEL;
        final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
        TouchTarget newTouchTarget = null;
        boolean alreadyDispatchedToNewTouchTarget = false;
--->    if (!canceled && !intercepted) {//未被取消并且未被打断
            ...
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                ...
                final int childrenCount = mChildrenCount;
                if (newTouchTarget == null && childrenCount != 0) {
                    ...
                    //这里接了一下mChildren,mChildren的初始化及添加操作稍后分析
                    final View[] children = mChildren;
        --->        for (int i = childrenCount - 1; i >= 0; i--) {//这里开始遍历所有的孩子
                        final int childIndex = customOrder
                                ? getChildDrawingOrder(childrenCount, i) : i;
                        final View child = (preorderedList == null)
                                ? children[childIndex] : preorderedList.get(childIndex);
                        ...
                        newTouchTarget = getTouchTarget(child);
                        ...
                        resetCancelNextUpFlag(child);
                        //dispatchTransformedTouchEvent会触发子View的d16t方法
                --->    if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                            // Child wants to receive touch within its bounds.---孩子想要在他的范围内接受触摸
                            ...
               --->        newTouchTarget = addTouchTarget(child, idBitsToAssign);
                            alreadyDispatchedToNewTouchTarget = true;
                            break;
                        }
                        ...
        // Dispatch to touch targets. ---- 分发到多个触摸点?...
        if (mFirstTouchTarget == null) {//mFirstTouchTarget在addTouchTarget方法中被赋值
--->        handled = dispatchTransformedTouchEvent(ev, canceled, null,
                    TouchTarget.ALL_POINTER_IDS);
        } else {
            TouchTarget predecessor = null;
            TouchTarget target = mFirstTouchTarget;
            //下面遍历target的链表,取出链表中的View执行dispatchTransformedTouchEvent
            while (target != null) {
                final TouchTarget next = target.next;
                if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                    handled = true;
                } else {
                    final boolean cancelChild = resetCancelNextUpFlag(target.child)
                            || intercepted;
        --->        if (dispatchTransformedTouchEvent(ev, cancelChild,
                            target.child, target.pointerIdBits)) {
                        handled = true;
                    }
                    if (cancelChild) {
                        if (predecessor == null) {
                            mFirstTouchTarget = next;
                        } else {
                            predecessor.next = next;
                        }
                        target.recycle();
                        target = next;
                        continue;
                    }
                }
                predecessor = target;
                target = next;
            }
        }
        ....
         return handled;
}

---->[ViewGroup#dispatchTransformedTouchEvent]----------------------------
|--总的来说就是触发super或是child的d16t方法,ViewGroup的super是谁?
|--答:View 。child 如果不为空走自己的d16t,如果child还是ViewGroup,就再走一圈上面的
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
        View child, int desiredPointerIdBits) {
...
    if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {//取消时
        event.setAction(MotionEvent.ACTION_CANCEL);
        if (child == null) {
--->        handled = super.dispatchTouchEvent(event);//孩子为空触发super的d16t,
        } else {
            handled = child.dispatchTouchEvent(event);//孩子不为空,触发d16t
        }
        event.setAction(oldAction);
        return handled;
    }

    if (newPointerIdBits == oldPointerIdBits) {
        if (child == null || child.hasIdentityMatrix()) {
            if (child == null) {
    --->        handled = super.dispatchTouchEvent(event);
            } else {
                ...
    --->        handled = child.dispatchTouchEvent(event);
            }
            return handled;
        }
        transformedEvent = MotionEvent.obtain(event);
    } else {
        transformedEvent = event.split(newPointerIdBits);
    }

    if (child == null) {
--->    handled = super.dispatchTouchEvent(transformedEvent);
    } else {
        ...
--->    handled = child.dispatchTouchEvent(transformedEvent);
    }
    transformedEvent.recycle();
    return handled;
}


---->[ViewGroup#addTouchTarget]----------------------------
private TouchTarget addTouchTarget(View child, int pointerIdBits) {
    TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
    target.next = mFirstTouchTarget;
    mFirstTouchTarget = target;
    return target;
}

---->[TouchTarget]----------------------------
|---描述触摸的View以及手指的id们
|---TouchTarget是ViewGroup的一个内部类,看样子是一个单链表
|---有一个next的TouchTarget字段,链表承载数据类型是View
private static final class TouchTarget {
    ...
    public View child;
    public TouchTarget next;
    ...
}

---->[ViewGroup$TouchTarget#obtain]----------------------------
|-- 这里很明显是第一个元素出链表
public static TouchTarget obtain(View child, int pointerIdBits) {
    final TouchTarget target;
    synchronized (sRecycleLock) {
        if (sRecycleBin == null) {
            target = new TouchTarget();
        } else {
            target = sRecycleBin;
            sRecycleBin = target.next;
            sRecycledCount--;
            target.next = null;
        }
    }
    target.child = child;
    target.pointerIdBits = pointerIdBits;
    return target;
}

---->[ViewGroup#onInterceptTouchEvent]---------------------------
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return false;
}
Copy the code

2. Of the ViewdispatchTouchEvent

It’s a relief to watch this…

public boolean dispatchTouchEvent(MotionEvent event) { if (event.isTargetAccessibilityFocus()) { if (! isAccessibilityFocusedViewOrHost()) { return false; } event.setTargetAccessibilityFocus(false); } boolean result = false; if (mInputEventConsistencyVerifier ! = null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } final int actionMasked = event.getActionMasked(); if (actionMasked == MotionEvent.ACTION_DOWN) { stopNestedScroll(); } the if (onFilterTouchEventForSecurity (event)) {/ / note that satisfy the four conditions, direct returns true, ListenerInfo Li = mListenerInfo; if (li ! = null && li.mOnTouchListener ! = null && (mViewFlags & ENABLED_MASK) == ENABLED ---> && li.mOnTouchListener.onTouch(this, event)) { result = true; } ---> if (! Result && onTouchEvent(event)) {// This triggers the onTouchEvent of the View!! Moved,... result = true; } } if (! result && mInputEventConsistencyVerifier ! = null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } if (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL || (actionMasked == MotionEvent.ACTION_DOWN && ! result)) { stopNestedScroll(); } return result; }Copy the code

About 4.onInterceptTouchEvent

In case you haven’t noticed, it’s been wiped out… It’s just a Boolean for control

---->[ViewGroup#onInterceptTouchEvent]--------------------------- public boolean onInterceptTouchEvent(MotionEvent ev) {  return false; }Copy the code

5. About:onTouchEvent
-- -- -- - > [Activity# onTouchEvent] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - | - poor, Is basically a false public Boolean onTouchEvent (MotionEvent event) {if (mWindow. ShouldCloseOnTouch (this event)) {finish (); return true; } return false; } -- -- -- - > [ViewGroup# onTouchEvent] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - | - yi, my onTouchEvent? There is no!!!! | - this makes me quite unexpected, that is, ViewGroup completely use the View onTouchEvent -- -- -- - > [View# onTouchEvent] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - | - this is a little bit the head... Public Boolean onTouchEvent(MotionEvent Event) {final float x = event.getx (); final float y = event.getY(); final int viewFlags = mViewFlags; final int action = event.getAction(); If ((viewFlags & ENABLED_MASK) == DISABLED) {if (action == motionEvent.action_up && (mPrivateFlags & PFLAG_PRESSED) ! = 0) { setPressed(false); } the return (((viewFlags & CLICKABLE) = = CLICKABLE / / directly go back to the | | (viewFlags & LONG_CLICKABLE) = = LONG_CLICKABLE) | | (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE); } if (mTouchDelegate ! = null) {/ / a touch agent if (mTouchDelegate. OnTouchEvent (event)) {/ / execution agent onTouchEvent return true; / / / / directly go back to}} the if (((viewFlags & CLICKABLE) = = CLICKABLE | | (viewFlags & LONG_CLICKABLE) = = LONG_CLICKABLE) | | (viewFlags &context_clickable) == CONTEXT_CLICKABLE) {// Switch (action) {// Switch (action) case ACTION_UP:// Boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED)! = 0; if ((mPrivateFlags & PFLAG_PRESSED) ! = 0 || prepressed) { boolean focusTaken = false; . If (prepressed) {// being pressed setPressed(true, x, y); // declare true} if (! mHasPerformedLongPress && ! MIgnoreNextUpEvent) {// This is a tap, so remove the longpress check-- removeLongPressCallback(); if (! focusTaken) { if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (! post(mPerformClick)) { performClick(); // Execute the click}}}... break; case MotionEvent.ACTION_DOWN: ... break; case MotionEvent.ACTION_CANCEL: ... break; case MotionEvent.ACTION_MOVE: ... break; } return true; } return false; } ---->[View#performClick]---------------------- public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li ! = null && li.mOnClickListener ! = null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); return result; }Copy the code
Addition: The ViewGroup adds a child View
-- -- -- - > [pair ViewGroup View to add] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- private View [] mChildren; mChildren = new View[ARRAY_INITIAL_CAPACITY]; / / the default 12 -- -- -- -- > [ViewGroup# addInArray] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- private void addInArray (View child, int index) { View[] children = mChildren; final int count = mChildrenCount; final int size = children.length; if (index == count) { if (size == count) { mChildren = new View[size + ARRAY_CAPACITY_INCREMENT]; System.arraycopy(children, 0, mChildren, 0, size); children = mChildren; } ---> children[mChildrenCount++] = child; } else if (index < count) { if (size == count) { mChildren = new View[size + ARRAY_CAPACITY_INCREMENT]; System.arraycopy(children, 0, mChildren, 0, index); System.arraycopy(children, index, mChildren, index + 1, count - index); children = mChildren; } else { System.arraycopy(children, index, children, index + 1, count - index); } ---> children[index] = child; mChildrenCount++; if (mLastTouchDownIndex >= index) { mLastTouchDownIndex++; } } else { throw new IndexOutOfBoundsException("index=" + index + " count=" + count); }} | - add the View about the ViewGroup, tracking the: addView (participate) - > addView (two arguments) - > addView (three arguments) - > addViewInner - > addInArrayCopy the code

Summary:

In general, the source code looks down, feel view event distribution mechanism is not as difficult as I imagined

In a custom View, that is, at most, ViewGroup+ child View touch event coordination. Activities usually do not participate in Activity event distribution, which is essentially a DecorView event distribution. Finally, I’d like to highlight the difference between d10t and O18t when they return false, which I was confused about before: see the image below


Finally, let’s use a small example to express througho18tTo control event response behavior

If the parent slides left, it doesn’t truncate the child View. If the parent slides right, it truncates the child View.

/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2019/2/21/021:9:06<br/> * Email: [email protected]<br/> * Description: Public class FatherViewGroup extends FrameLayout {private static final String TAG = "EventTest"; boolean isLeft = false; public FatherViewGroup(Context context) { super(context); } public FatherViewGroup(Context context, AttributeSet attrs) { super(context, attrs); setBackgroundColor(0xff9869B7); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return isLeft; } float x; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: x = event.getX(); break; case MotionEvent.ACTION_MOVE: float curX = event.getX(); float dx = curX - this.x; isLeft = dx < 0; x = curX; setBackgroundColor(ColUtils.randomColor()); break; } return true; } /** * Author: Zhang Fengjie Teilie <br/> * Time: 2019/2/21/021:9:06<br/> * Email: [email protected]<br/> * Description: Public class SonView extends View {private static final String TAG = "EventTest"; public SonView(Context context) { super(context); } public SonView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); setBackgroundColor(0xffE58F46); } float x; @Override public boolean onTouchEvent(MotionEvent event) { setBackgroundColor(ColUtils.randomColor()); return true; }}Copy the code

Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of The appendix
V0.1– The 2018-2-21 There is no

Release name: Android Event Distribution Mechanism [source level]

Jiwen link: juejin.cn/post/684490…

2. More about me
Pen name QQ WeChat
Zhang Feng Jie te Li 1981462002 zdl1994328

3. The statement

1—- this article is originally written by Zhang Feng Jetelie, please note 2—- all programming enthusiasts are welcome to communicate with each other 3—- personal ability is limited, if there is any error, you are welcome to criticize and point out, will be modest to correct 4—- See here, I thank you here for your love and support