Talk about event distribution again

Talk about event distribution again

Preface

"Big brother, big brother, come on, the leader asks you to come to the interview!!"

"I'm coming!"

Looking at the resume, the interview was for intermediate Android development.

"Tell me about the Android event distribution mechanism!"

"Big brother, to be honest, I don't know how to distribute the incident. Fortunately, you raised your hand when you interviewed me. You didn't ask me. If you ask me, I won't be able to join our company!"

"Raise your hand, when you were interviewing an intern, I asked you what you are doing?"

"Oh, all right...Speaking of which, brother, can you tell me about the event distribution?"

"Okay, I'll tell you from beginning to end, this will be useful in the future."

"Thank you, big brother, I'll make coffee for big brother!!!"

text

Event distribution is a common question in Android development. It is not only used to deal with interviews, but also often used in actual work. (Here I want to explain, usually try to learn more firmly, don't wait until the interview. ). Next, I will distribute the event and take a good look!

Activity composition

"Boy, tell me about the composition of Activity!"

"Form? Activity is not Activity! What composition?"

"... I remembered..."

An Activity contains a Window object, and Window is implemented by PhoneWindow. PhoneWindow regards DecorView as the root View of the entire application window, and this DecorView divides the screen into two areas: one is TitleView, the other is ContentView, and what we usually write is displayed in ContentView.

"It seems to understand a little bit, but brother, what does this have to do with the distribution of the event?"

"The monkey's anxious temperament just can't be changed, I'll talk about it soon!"

Event type

Touch events correspond to the MotionEvent class. There are three main types of events:

  • ACTION_DOWN is triggered when the screen is pressed
  • ACTION_MOVE is triggered when sliding on the screen (the movement distance exceeds a certain threshold will be judged as an ACTION_MOVE operation)
  • ACTION_UP is triggered when the screen is raised
  • ACTION_CANCLE Triggered when sliding beyond the control boundary

"Brother, what is the threshold you just said? I remember reading other people's blogs and saying the same before, but I haven't figured out what the threshold is?"

"Not bad, kid, I'm very curious!"

TouchSlop (system constant) represents the minimum movement threshold, and the default value is generally 8dp. I believe this can be understood, which means that if you slide less than this value, the system will think that you are not a sliding event. It should be noted here that some mobile phone manufacturers reset this value in order to "improve the user experience". If you are unsure, you can print it out.

Log.i("ViewConfiguration", "TouchSlop=" + ViewConfiguration.get(this).scaledTouchSlop)

The following is the execution result:

2020-05-07 22:12:35.939 12599-12599/com.zj.weather I/ViewConfiguration: TouchSlop=21

"do you understand?"

"Uh, uh... elder brother, go ahead, I can understand!"

In fact, the essence of View event distribution is very simple. When a MotionEvent event occurs, the system transmits the click event to a specific View, which is the process of distributing MotionEvent events.

Event distribution process

"Boy, come and tell me which methods are used to complete the event distribution process!"

"Hmm... There are dispatchTouchEvent, and onInterceptTouchEvent and onTouchEvent three methods are completed."

"Not bad, then you can tell me about the execution process of these three methods"

"Brother, just speak directly, I only know that there are three methods..."

"Okay, don't embarrass you, I have to listen carefully."

Let's talk about each method one by one!

**dispatchTouchEvent (distribution): **When the method returns true, it means that the event is consumed by the current view; if it returns false, it means it is handed over to the onTouchEvent in the parent class for processing; if it returns to super.dispatchTouchEvent, it means it will Continue to distribute the event.

**onInterceptTouchEvent (intercept): **When the method returns true, it means that the event is intercepted and handed over to its own onTouchEvent method for consumption; if it returns false, it means that it is not intercepted and needs to be passed to the subview. If it returns super.onTouchEvent(ev), this block is a bit troublesome, and it is divided into two cases:

  • If the View has a child View and the child View is clicked, it will not be intercepted and will continue to be distributed to the child View for processing, which is equivalent to returning false
  • If the View has no child View or child View but does not click on the neutron View (ViewGroup is equivalent to a normal View), the onTouchEvent response of the View will be sent to the View, which is equivalent to returning true.

It should be noted that: LinearLayout, RelativeLayout, FrameLayout and other ViewGroups are not intercepted by default , while ViewGroups such as ScrollView and ListView may be intercepted , depending on the specific situation.

**onTouchEvent (consumption): **The return value of the method is true, which means that the current view can handle the corresponding event; the return value is false, which means that the current view does not handle this event, and it will be passed to the onTouchEvent method of the parent view for processing. If it returns super.onTouchEvent(ev), the event processing is divided into two situations:

  • If the View is clickable or longclickable, it will return true, indicating that the event was consumed, the same as returning true
  • If the View is not clickable or longclickable, it will return false, which means that the event will not be consumed and will be passed upwards, just like returning false.

"Kid, understand? The so-called event distribution is that simple"

"Ah? What is all this! I don't understand at all, brother, can you talk more about it?"

"I really can't help you, okay, listen up!"

You see, there are three types of events in Android: Activity, ViewGroup, and View . You think, what do Activity and View do to intercept events? They don't care, so it's enough for them to distribute and consume. But ViewGroup is different. It will contain sub-Views, so it needs to intercept events, right? Forget it, write you a pseudo code!

fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
    
    
        var result = false
        if (onInterceptTouchEvent(ev)) {
    
    
            result = onTouchEvent(ev)
        } else {
    
    
            result = child.dispatchTouchEvent(ev)
        }
        return result
    }

"Boy, do you think this will work?"

"Um... Brother, you can talk about it..."

Look at the above code, corresponding to a root ViewGroup, after a click event is generated, it will be passed to it first, and its dispatchTouchEvent method will be called at this time . If the onInterceptTouchEvent method of this ViewGroup returns true, it means that it wants to intercept the current event. , Then the event will be handed over to this ViewGroup for processing, then if its mOnTouchListener is set, onTouch will be called, otherwise onTouchEvent will be called. In onTouchEvent, if the set mOnCLickListener , the onClick is invoked. It should be noted here that as long as one of the CLICKABLE and LONG_CLICKABLE of the View is true, onTouchEvent will return true to consume this event; if the onInterceptTouchEvent method returns false, it means that it does not intercept the current event, and the current event will continue to be passed to its child elements. , Then the dispatchTouchEvent method of the child element will be called, and it will repeat until the event is finally processed.

"Boy, isn't it easy?"

"It's very simple to hear, but I still have to digest it!"

"Well, indeed, this piece is actually very troublesome. To put it simply, it will be more troublesome to deal with sliding conflicts if multiple sliding layouts are nested. Let me summarize it for you!"

Small summary

  • Event delivery priority: onTouchListener.onTouch> onTouchEvent> onClickListener.onClick
  • ViewGroup does not intercept any events by default (returns false)
  • View's onTouchEvent will consume events by default (returns true), unless it is not clickable (clickable and longClickable are both false)
  • The longClickable attribute of View is false by default , and the clickable attribute depends on the situation. For example, the clickable attribute of Button is true by default, and the clickable of TextView is false by default.
  • The enable attribute of View does not affect the default return value of onTouchEvent
  • The requestDisallowInterceptTouchEvent method can intervene in the event distribution process of the parent element in the child element, except for the ACTION_DOWN event

"Keep these points in mind, you will understand it faster!"

"Thank you brother!"

Problems in development

"By the way, when will ACTION_CANCEL be triggered? If you touch the button and then slide to the outside to lift it, will it trigger a click event, and then slide it back to lift it?"

"Can you ask one question by one question..."

  • Generally, ACTION_CANCEL and ACTION_UP are regarded as the end of View event processing. If ACTION_UP or ACTION_MOVE is intercepted in the parent View, at the moment when the parent view intercepts the message for the first time, the parent view specifies that the child view does not accept subsequent messages, and the child view will receive the ACTION_CANCEL event.
  • If you touch a control, but it is not lifted (moved to another place) on the area of ​​the control, ACTION_CANCEL will appear.

"Understood?"

"Hmm, I know this, but I still have a problem. If the click event is intercepted, but I want to send it to the View below, what should I do?"

"It's simple! As long as you override the requestDisallowInterceptTouchEvent() method of the subclass to return true, the onInterceptTouchEvent() of the parent class will not be executed, and the click event can be passed to the View below."

"Brother, how do I resolve the sliding conflicts I usually encounter?"

"This is more troublesome to talk about, maybe I will give you some ideas, this needs you to slowly experience it in future development!"

Rules for handling sliding conflicts:

  • For sliding conflicts caused by inconsistent external sliding and internal sliding directions, it is possible to determine who intercepts the event based on the sliding direction.
  • For sliding conflicts caused by the consistency of the external sliding direction and the internal sliding direction, you can specify when the external View will intercept the event and when the internal View will intercept the event according to business requirements.
  • For the nesting of the above two situations, it is relatively complicated, and you can also find a breakthrough in the business according to the needs.

Implementation method of sliding conflict:

  • External interception method: It means that click events are intercepted by the parent container first. If the parent container needs this event, it will intercept it, otherwise it will not be intercepted. Specific method: need to rewrite the onInterceptTouchEvent method of the parent container and make corresponding interception internally.
  • Internal interception method: means that the parent container does not intercept any events, but passes all events to the child container. If the child container needs this event, it will be consumed directly, otherwise it will be handed over to the parent container for processing. Specific method: need to cooperate with requestDisallowInterceptTouchEvent method

to sum up

"Boy, this is always okay?"

"Big brother, I still have questions..."

"Let me go, it's so late, let's talk about it tomorrow if you have any questions!"

This article briefly describes the event distribution mechanism of Android. The description is not particularly detailed. You can write a small Demo to try and deepen your understanding. The article has been written in a hurry, if there are errors, please point them out in the comment area, thank you! If you like, please like and follow!

Guess you like

Origin blog.csdn.net/haojiagou/article/details/105987412