天天看點

Android滑動沖突

      • Android滑動沖突
      • 如何解決滑動沖突
        • 内部攔截法
        • 外部攔截法
        • 分析滑動沖突的解決

Android滑動沖突

Android的滑動沖突主要有兩種情況:

1. 外部滑動方向和内部滑動方向不一緻–類似viewpager中放入listview

2. 外部滑動方向和内部滑動方向相同

其他的則是将這兩種沖突進行嵌套的情況。

如何解決滑動沖突

對于滑動沖突,我們隻需要各自攔截自己需要的事件即可。

那麼如何攔截各自需要的事件,由之前的文章View的事件分發機制可以知道可以通過兩種方法進行實作:

1. 内部攔截法

即父容器先對事件進行分析,如果是自己需要的事件,則進行攔截,如果不是自己需要的,則交給子view/viewgroup進行處理;

父容器中事件攔截的邏輯如以下代碼所示:

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercept = false;
        switch(ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                intercept = false;
                break;
            case MotionEvent.ACTION_MOVE:
                if(滿足我們需要的條件){
                    intercept = true;
                }else{
                    intercept = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                intercept = false;
                break;
            default:
                break;
        }
        return intercept;
    }
           

其中ACTION_DOWN事件不能進行攔截,因為在之前分發機制的分析時我們發現,如果攔截了ACTION_DOWN事件,那麼之後的所有事件都會交給攔截的view進行處理。而我們在解決滑動沖突的時候,隻需要攔截自己需要的事件,不需要的還要交給子容器進行處理,此處主要指ACTION_MOVE事件。同樣由分發機制可以知道,即使父容器不攔截ACTION_DOWN事件,隻要子元素不對父容器進行幹預,父容器還是能夠擷取ACTION_MOVE和ACTION_UP事件。

而對于ACTION_UP事件,父容器不需要進行攔截,因為我們的處理邏輯是在ACTION_MOVE中的,ACTION_UP對于滑動沖突沒有意義,同時,如果我們攔截了ACTION_UP,那麼該事件就不會傳遞到子view中,将會導緻onClick事件(如果有的話)無法觸發,是以不需要對ACTION_UP事件進行攔截。

2.外部攔截法

即父容器不攔截事件,所有時間傳遞給子元素,如果子元素看到父元素需要的事件,則将此事件交給父容器進行處理,否則繼續進行傳遞。

子容器中的寫法:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                if (滿足父容器所需要的條件){
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
           

由之前的事件分發機制可以知道,disallowIntercept可以影響目前容器的事件攔截,即是否經過onInterceptTouchEvent方法,此處通過getParent().requestDisallowInterceptTouchEvent(true/false)設定父容器的攔截,即當ACTION_DOWN事件到子容器的時候,将父容器的disallowIntercept設定為true,那麼後續的事件都不會經過父容器onInterceptTouchEvent而是直接傳遞給子容器,當後續事件是滿足父容器的需要的時候,再将disallowIntercept設定為false,那麼就會進入父容器的onInterceptTouchEvent,然後父容器對該事件進行處理。

是以同時需要改寫父容器onInterceptTouchEvent,代碼如下所示:

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(ev.getAction() == MotionEvent.ACTION_DOWN){
            return false;
        }else{
            return true;
        }
    }
           

即父容器攔截除了ACTION_DOWN之外的所有事件,不過onInterceptTouchEvent的調用時機是由子容器進行控制的。兩者需要進行配合進行使用。

3.分析滑動沖突的解決

然後我們再回頭看常見的滑動沖突,面對第一種情況,即内外滑動方向相反的情況,假設外層水準滑動,内層水準滑動,那麼我們隻需要外層攔截水準滑動距離大于垂直距離或者水準滑動速度大于垂直滑動速度的事件,内層攔截的相反即可。對于内外兩層滑動方向相同的則需要根據我們具體的業務邏輯需求進行判斷,多層嵌套的隻需要根據這兩種進行組合即可。

繼續閱讀