View sliding conflict

1. Common conflict scenarios: 
(1) The inconsistency between the external sliding direction and the internal sliding direction is 
mainly the page sliding effect composed of the combination of ViewPager and Fragment, and almost all mainstream applications use this effect. In this effect, you can switch pages by swiping left and right, and each page is often a ListView inside. In this case, there is a sliding conflict, but ViewPager handles this sliding conflict internally, so we don't need to pay attention to this problem when using ViewPager. However, if we use ScrollView, etc., we need to manually handle the sliding conflict, otherwise the consequence is that only one layer of the inner and outer layers can slide, because the sliding events between the two conflict. In addition, there are other situations, such as external sliding up and down, internal sliding left and right, etc., but they belong to the same type of sliding conflict. 
(2) The external sliding direction is the same as the internal sliding direction. 
When both the inner and outer layers can slide in the same direction, there is obviously a logical problem. Because when the finger starts to slide, the system cannot know which layer the user wants to slide, so there is a problem when the finger slides, either only one layer can slide, or both the inner and outer layers are very stuck. In actual development, this scenario mainly means that the inner and outer layers of View can slide up and down at the same time or can slide left and right at the same time. 
(3) The nesting 
of the above two cases is the nesting of the above two cases, so his sliding conflict looks more complicated. For example: the inner layer has a sliding effect of scene 1, and then the outer layer has a sliding effect of scene 2. Specifically, there is a SlideMenu effect outside, and then there is a ViewPager inside, and each page of ViewPager is a ListView. Although it looks more complicated, it is a superposition of several single sliding conflicts, so only the sliding conflicts between the inner layer and the middle layer, and the middle layer and the outer layer need to be dealt with separately.

Essentially, the complexity of these three sliding conflict scenarios is actually the same, because their difference is only the sliding strategy. The method of resolving sliding conflicts is basically handled by using internal interception and external interception.

Second, the solution to the sliding conflict 
1. External interception method 

The external interception method means that the click events are first intercepted by the parent container. If the parent container needs this event, it will be intercepted. If not, it will not be intercepted, so that the problem of sliding conflicts can be solved. This method is more in line with the distribution of click events. mechanism. External interception needs to rewrite the onInterceptTouchEvent method of the parent container and do the corresponding interception internally.

The corresponding pseudocode is as follows:

public boolean onInterceptTouchEvent(MotionEvent event){
    boolean intercepted=false;
    int x=(int)event.getX();
    int y=(int)event.getY();
    switch(event.getAction){
        case MotionEvent.ACTION_DOWM:
            intercepted=false;
        break;
        case MotionEvent.ACTION_MOVE:
          if(父容器需要当前点击事件){
              intercepted=true;
          }else{
              intercepted=false;
          }
        break;
        case MotionEvent.ACTION_UP:
            intercepted=false;
        break;
    }
    mLastXIntercept=x;
    mLastYIntercept=y;
    return intercepted;
}

The above code is the typical logic of the external interception method. For different sliding conflicts, it is only necessary to modify the condition that the parent container needs the current click event, and nothing else needs to be modified. 
In the onIntercepetTouchEvent method: 
(1) For the ACTION_DOWN event, the parent container must return false, that is, the ACTION_DOWN event is not intercepted. This is because once the ACTION_DOWN event is intercepted, the subsequent ACTION_MOVE and ACTION_UP events will be directly handled by the parent container. It can no longer be passed to child elements; 
(2) ACTION_MOVE event, this event can be intercepted according to requirements, if the parent container needs to intercept, it will return true, otherwise it will be false; 
(3) ACTION_UP event, here must return false, Because the ACTION_UP event itself doesn't make much sense.

Assuming that the event is handled by the child element, if the parent container returns true at ACTION_UP, the child element cannot receive the ACTION_UP event. At this time, the onClick event of the child element cannot be triggered, but the parent container is special. Once it starts to intercept any An event, then subsequent events will be handed over to it for processing, and ACTION_UP as the last event must be passed to the parent container, even if the onInterceptTouchEvent method of the parent container returns false in ACTIPN_UP.

2. Internal interception method The 
internal interception method means that the parent container does not intercept any events, and all events are passed to the child elements. If the child elements need it, they are directly consumed, otherwise they are handed over to the parent container for processing. This method is similar to Android's The event distribution mechanism is inconsistent and needs to work with the requestDisallowInterceptTouchEvent method, which is slightly more complicated to use than external interception. You need to override the dispatchTouchEvent method of the child element,

The dispatchTouchEvent method of the child element needs to be rewritten. The pseudo code is as follows:

public boolean dispatchTouchEvent(MotionEvent event){
    int x=(int)event.getX();
    int y=(int)event.getY();

    switch(event.getAction){
        case MotionEvent.ACTION_DOWN:
            parent.requestDisallowInterceptTouchEvent(true);
            break;

        case MotionEvent.ACTION_MOVE:
            int deltaX=x-mLastX;
            int daltaY=y-mLastY;
            if(父容器需要此类点击事件){
                parent.requestDisallowInterceptTouchEvent(false);
            }
            break;

       case MotionEvent.ACTION_UP:
           break;
    }
    mLastX=x;
    mLastY=y;
    return super.dispatchTouchEvent(event);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

When faced with different sliding strategies, you only need to modify the conditions inside, and others do not need to be changed. In addition to the child elements that need to be processed, the parent element also needs to intercept other events except ACTION_DOWN by default, so that when the child element calls the parent.requestDisallowInterceptTouchEvent(false) method, the parent element can continue to intercept the required events.

Because the ACTION_DOWN event is not controlled by the flag FLAG_DISALLOW_INTERCEPT, once the parent container intercepts the ACTION_DOWN event, all events cannot be passed to the child elements, so the internal interception will not work. So the parent element needs to be modified as follows:

public boolean onInterceptTouchEvent(MotionEvent event){

    int action=event.getAction();
    if(action==MotionEvent.ACTION_DOWN){
     return false;
    }else{
     return true;
      }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

The above two methods can basically perfectly solve the sliding conflict problem encountered in development.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324511110&siteId=291194637