The author blog

http://www.jianshu.com/u/0d03dcfbfc36

The article directories

  1. preface

  2. Common scenarios and handling ideas of sliding conflicts

  3. Sliding conflict resolution routines

    1. External interception

    2. Internal interception method

  4. Slide sample conflict resolution code

preface

In the last article we talked about the “Android View event distribution mechanism.” If you are not familiar with the View event distribution, it is recommended to read the article to understand the Android View event distribution mechanism, which is our theoretical basis for sliding conflict resolution today!

If you already know the View event distribution mechanism, then we will talk about the View event distribution mechanism in detail.

2

Common scenarios and handling ideas of sliding conflicts

When we can slide both the inner and outer layers of the View, there will be sliding conflicts!

Common sliding conflict scenarios:

  1. The outer layer slides in a different direction from the inner layer. The outer layer ViewGroup slides horizontally and the inner layer View slides vertically (similar to ViewPager, where each page is a ListView).

  2. The outer layer slides in the same direction as the inner layer. The outer ViewGroup slides vertically, and the inner View slides vertically (similar to ScrollView wrapped around ListView).

Of course, there are also the above two kinds of combination, three or more layers of nested conflict, but no matter how complex, the solution is the same idea. So don’t panic when you encounter multiple nested partners, just deal with them one by one.

ViewPager with ListView does not appear to slide conflict.

That’s because ViewPager already handles slide collisions for us! If we define a horizontal sliding ViewGroup and then use the ListView internally, we will definitely need to handle sliding conflicts.

For the first scenario above, since the sliding directions of external and internal are not consistent, we can determine who should handle the event according to the current sliding direction, horizontal or vertical. As for how to get the direction of slide, we can get the coordinates of the two points during the slide. In general, the direction can be judged according to the distance difference between horizontal and vertical sliding direction. Of course, it can also be judged according to the included Angle (or slope as shown in the figure below) formed by the sliding path and the sliding speed difference between horizontal and vertical direction.

ViewPager intercepts the event if the slope is less than 0.5

Interested friends can see ViewPager source analysis: sliding and conflict processing (http://blog.csdn.net/huachao1001/article/details/51654692)

For the second scenario, as the sliding direction of the external and internal is the same, it cannot be judged according to the sliding Angle, distance difference or speed difference. In this case, business logic is required. A common ScrollView has a nested ListView. While the requirements and business logic are naturally different, the way to resolve sliding conflicts is the same. Below is a screenshot of the conflict scene of sliding in the same direction between Weibo and Tmall, so that you can feel this scene more intuitively.

Same direction, vertical slide conflict

This scene of weibo is in the same direction and vertical sliding conflict. It can be seen that the overall layout can be scrolled, and the list of weibo below can also be scrolled. According to business logic, when the hits, the charts… The list of tweets can only be scrolled when this line of tabs slides to the top. Otherwise, you find the overall scrolling of the layout. This scene can be seen in many apps!

Same direction, lateral slide conflict

This scene of Tmall shows the conflict of horizontal sliding in the same direction. Both the inner and outer layers can be rolled horizontally. Its processing logic is also obvious, according to the user slide position to determine which View needs to respond to the slide.

The only difference between the two sliding conflict scenarios is the logical handling of interception. The first is based on horizontal or vertical sliding to determine who handles the slide, and the second is based on business logic to determine who handles the slide, but the process is the same

3

Sliding conflict resolution routines

Routine 1 External intercept method:

That is, the parent View intercepts events as needed. The logical processing is placed in the parent View’s onInterceptTouchEvent method. We just need to rewrite the parent View’s onInterceptTouchEvent method and intercept it accordingly.

The above pseudocode represents the external interception method. Note the following points



  • According to the business logic needs, judge in the ACTION_MOVE method, if the parent View needs to process, return true, otherwise return false, the event is distributed to the child View to process.

  • ACTION_DOWN must return false, do not intercept it, otherwise according to the View event distribution mechanism, subsequent ACTION_MOVE and ACTION_UP events will be handed to the parent View by default!

  • In principle, ACTION_UP should also return false. If true is returned and the sliding event is handed to the child View, the child View will not receive the ACTION_UP event and the child View’s onClick event will not fire. If the parent View starts intercepting events in ACTION_MOVE, then the subsequent ACTION_UP will also be handed over to the parent View by default!

Routine two internal interception method:

That is, the parent View does not intercept any events, all events are passed to the child View, the child View as needed to decide whether to consume the event itself or to the parent View processing. The child View use requestDisallowInterceptTouchEvent method is needed to work properly. Here is the pseudo-code for the dispatchTouchEvent method of the child View:

The parent View needs to override the onInterceptTouchEvent method:

Note the following when using internal interception:

  • Internal interception requires that the parent View not intercept ACTION_DOWN events. Since ACTION_DOWN is not controlled by the FLAG_DISALLOW_INTERCEPT bit, once the parent intercepts an ACTION_DOWN event, no event is passed to the child View.

  • Sliding strategy View, the logic on the son of dispatchTouchEvent ACTION_MOVE method, call the parent if the parent container need access to click events. RequestDisallowInterceptTouchEvent (false) method, Let the parent container intercept the event.

4

Slide sample conflict resolution code

The final foot of the theory is in practice, below I use an example to demonstrate the external solution method and internal solution method to solve the sliding conflict, as long as we get the essence of the sliding conflict problem will be solved in the future, is no longer a development block!

We said at the beginning that the ViewPager handles sliding conflicts by default, and that as a ViewGroup it uses external intercepting to resolve conflicts, which is determined in the onInterceptTouchEvent method. To create a sliding conflict scenario, we’ll define a ViewPager that overwrites the onInterceptTouchEvent method and returns false by default, as follows:

Thus, a good ViewPager is corrupted by us!

Next, create a ScrollConflicActivity to test for sliding conflicts.



Note: Flowable is the RxJava2 method, and the same is true with the for loop



The above code uses BadViewPager to initialize the child View in BadViewPager. initData(false); The false method means that the child View is a TextView, and the true method means that the child View is a ListView. First let’s see if the BadViewPager face View is a TextView can slide.

It doesn’t seem to have any effect on BadViewPager sliding.

BadViewPager onInterceptTouchEvent (BadViewPager onInterceptTouchEvent) returns false by default, so all events will be handled by the child View. Remember the principle of View handling events from the last article?

A View’s onTouchEvent method will consume the event by default (returning true), unless it is unclickable (both Clickable and longClickable are false), and a View’s longClickable is false by default, Clickable needs to be differentiated, such as Button clickable defaults to true and TextView clickable defaults to false.

So TextView doesn’t have a consumption event by default because it’s unclickable. The event is handled by the onTouchEvent method of the parent View, BadViewPager. So of course it can slide.

We set the Clickable of the TextView to true, that is, to consume events. Let’s see

So it’s not hard to guess that if you replace TextView with Button, it will have the same effect. Although this is not a normal slide conflict (the child View is not sliding), the cause is the same: the parent View does not respond properly to the slide.

Next modify the code initData(true) slightly; If we pass true, the child of BadViewPager will use ListView. ListView can slide, BadViewPager can’t slide. BadViewPager is fixed by external and internal interception methods, respectively.

1. Fix BadViewPager:


According to our external intercepting routine, we need to override the BadViewPager onInterceptTouchEvent method with ACTION_DOWN and ACTION_UP returning false. In ACTION_MOVE, math.abs (deltaX)> math.abs (deltaY) means that the increment of horizontal displacement is greater than the increment of vertical displacement, i.e. horizontal sliding, BadViewPager intercepts the event.

Here we are in the midst of ACTION_DOWN. Also called super onInterceptTouchEvent (ev); The onInterceptTouchEvent method of ViewPager. It is used to initialize the ViewPager member variable mActivePointerId. MActivePointerId defaults to -1, and in the ACTION_MOVE of ViewPager’s onTouchEvent method there is a section like this:

If the mActivePointerId is not initialized, the ViewPager will assume that the event has been consumed by the View, then break, and the subsequent slide operation will not be performed.

2. Fix BadViewPager:

Internal interception requires overwriting the ListView dispatchTouchEvent method, so we’ll create a custom ListView:


Looking at BadViewPager, you need to override the interception method

It can be seen that the routine code is basically the same as ours, except that ACTION_MOVE has our own logic processing, and the processing method is consistent with the external interception method, and the effect is the same, I will not repeat it here.

All you need to do is to master the sliding conflict resolution routines described above. No matter the scene is in different directions, in the same direction, or in a jumble of piles, you can use the routines to solve the sliding conflict. As you can see from the above external intercepting and internal intercepting methods, external intercepting is easier to implement and also conforms to the View’s normal event distribution mechanism. Therefore, it is recommended to use external intercepting method (overriding the onInterceptTouchEvent of the parent View, and the parent View decides whether to intercept or not) to handle sliding conflicts


Please feel free to tip me if this article has been useful to you.

Reward

people gave a reward

Long press the QR code to transfer money to me

Please feel free to tip me if this article has been useful to you.

Due to apple’s new regulations, the appreciation function of the iOS version of wechat has been disabled, and qr code transfer can be used to support public accounts.

Read more

Report

Scan QR Code via WeChat to follow Official Account