解決ScrollView嵌套viewPager中嵌套listView滑動事件衝突問題(水平方向)

我們在開發中經常會碰到view滑動衝突的情況。

滑動衝突的解決辦法就兩種:

1.外部攔截法:是指在點擊事件先經過父容器的攔截處理,如果父容器需要處理此事件就進行攔截,如果不需要此事件就不攔截,這樣就可以解決滑動衝突的問題,外部攔截法需要重寫父容器的onInterceptTouchEvent()方法,在內部做相應攔截處理。

2.內部攔截法:是指點擊事件先經過子View處理,如果子view需要次事件就直接消耗掉,否則就交給父容器進行處理,這樣就可以解決滑動衝突的問題。內部攔截需要配合requestDisallowInterceptTouchEvent()方法,來確定子view是否允許父容器攔截事件。

    a.允許父容器進行事件攔截

        getParent().requestDisallowInterceptTouchEvent(false)

    b.禁止父容器進行事件攔截

        getParent().requestDisallowInterceptTouchEvent(true)


以上是解決滑動衝突的方法,下面我們回到我們今天解決的正題ScrollView嵌套viewPager中嵌套listView滑動事件衝突

這裏可以使用第一種解決方案:外部攔截法

只需要自定義一個ScrollView,然後重寫它的onInterceptTouchEvent()即可,代碼如下:

public class VerticalScrollView extends ScrollView {

    private float xDistance, yDistance, xLast, yLast;

    public VerticalScrollView(Context context) {
        super(context);
    }

    public VerticalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public VerticalScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                xDistance = yDistance = 0f;
                xLast = ev.getX();
                yLast = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                final float curX = ev.getX();
                final float curY = ev.getY();

                xDistance += Math.abs(curX - xLast);
                yDistance += Math.abs(curY - yLast);
                xLast = curX;
                yLast = curY;

                if (xDistance > yDistance) {
                    return false;
                }
        }
        return super.onInterceptTouchEvent(ev);
    }

}

第二種解決方案如下:不需要自定義控件

1.第一步:允許父容器進行事件攔截

scrollView.setOnScrollToBottomLintener(new BottomScrollView.OnScrollToBottomListener() {
    @Override
    public void onScrollBottomListener(boolean isBottom) {
        if (isBottom) {
            scrollView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_MOVE:
                            //解決滑動衝突

                            scrollView.getParent().requestDisallowInterceptTouchEvent(false);
                            break;
                    }
                    return false;
                }
            });
        }
    }
});

2.第二步:父元素也要默認攔截除了ACTION_DOWN以外的其他事件,這樣當子元素調用

scrollView.getParent().requestDisallowInterceptTouchEvent(false)

方法時,父元素才能繼續攔截所需的事件。

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    int action = ev.getAction();
    return action != MotionEvent.ACTION_DOWN; 
}

3.爲什麼父容器不能攔截ACTION_DOWN事件呢?

    因爲ACTION_DOWN事件並不受FLAG_DISALLOW_INTERCEPT這個標記位的控制,所以一旦父容器攔截ACTION_DOWN事件,那麼所有的事件都無法傳遞到子元素中去,這樣內部攔截就無法起作用了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章