Viewpager和SeekBar的滑動衝突的解決辦法(其他滑動衝突可參考)

Android開發中滑動衝突非常常見,下面介紹一下我在項目開發中遇到的問題及解決方法。

一、問題描述:在ViewPager+Fragment的配合使用中,在fragment的佈局中使用到了SeekBar,此時會出現SeekBar只在第一次滑動的時候好用,之後的滑動都只能ViewPager有效,SeekBar滑動失效。
二、解決辦法:重新自定義ViewPager和SeekBar,代碼如下:

自定義的ViewPager

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

/**
 * Created by leven on 2017/4/20.
 */

public class NoScrollViewPager extends ViewPager {

    private boolean noScroll = false;

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

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

    //控制是否可滑動
    public void setNoScroll(boolean noScroll) {
        this.noScroll = noScroll;
    }

    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
    }

    @Override
    public boolean onTouchEvent(MotionEvent arg0) {
        if (noScroll)
            return false;
        else
            return super.onTouchEvent(arg0);
    }

    //請求允許打斷滑動或不允許打斷該組件的滑動事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        if (noScroll){
            getParent().requestDisallowInterceptTouchEvent(false);
            return false;
        } else{
            return super.onInterceptTouchEvent(arg0);
        }

    }

    @Override
    public void setCurrentItem(int item, boolean smoothScroll) {
        super.setCurrentItem(item, smoothScroll);
    }

    @Override
    public void setCurrentItem(int item) {
        super.setCurrentItem(item);
    }

}

自定義的SeekBar

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.SeekBar;

import com.dfwy.cxy.xiahubao.message.MessageEvent;

import org.greenrobot.eventbus.EventBus;

/**
 * Created by leven on 2017/5/4.
 */

public class ScrollableSeekBar extends SeekBar {

    boolean touchingProgressBar = true;

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

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

    public ScrollableSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setTouchingProgressBar(boolean touchingProgressBar) {
        this.touchingProgressBar = touchingProgressBar;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(touchingProgressBar){
            super.onTouchEvent(event);

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    System.out.println("MotionEvent.ACTION_DOWN");
                    //請求觸摸事件不被打斷
                    getParent().requestDisallowInterceptTouchEvent(true);
                    touchingProgressBar = true;
                    break;
                case MotionEvent.ACTION_UP:
                    System.out.println("MotionEvent.ACTION_UP");
                    //當結束滑動時請求觸摸事件可以被打斷
                    getParent().requestDisallowInterceptTouchEvent(false);
                    touchingProgressBar = true;
                    break;
                case MotionEvent.ACTION_CANCEL:
                    getParent().requestDisallowInterceptTouchEvent(false);
                    break;
            }
        } else {

        }
        return true;
    }

    //此處非常重要, 返回true,後續事件(ACTION_MOVE、ACTION_UP)會再傳遞
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        System.out.println("dispatchTouchEvent");
        super.dispatchTouchEvent(event);
        return true;
    }
}

SeekBar在代碼中的操作

    mSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
        @Override
        public void onProgressChanged(SeekBar seekBar,int i,boolean b){

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar){
            //發送通知讓ViewPager不可滑動
        getParentFragment()).getViewPagerTask().setNoScroll(true);
            EventBus.getDefault().post(new MessageEvent("NoScrollableViewPager"));
            if(seekBar.getParent()!=null){
                seekBar.getParent().requestDisallowInterceptTouchEvent(true);
            }
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar){
            //發送通知讓ViewPager可滑動
            EventBus.getDefault().post(new MessageEvent("ScrollableViewPager"));
            getParentFragment()).getViewPagerTask().setNoScroll(false);
            surveyChoiceListBean.setVALUE(String.valueOf(seekBar.getProgress()-100));
        }

總結:這裏主要是滑動事件的滑動順序及處理,事實上,滑動事件的分發機制還是稍微有點複雜的,首先執行的是父組件的dispatchTouchEvent方法,返回true時繼續向下傳遞,此時可以控制父組件的滑動方法讓其不可滑動,然後事件傳遞到子組件的dispatchTouchEvent方法,該方法返回true繼續傳遞到該組件的滑動方法,然後可以在滑動方法中做一些操作,在滑動執行完成時可以讓父組件的滑動恢復正常,這就是我在解決滑動衝突的思路,希望可以給大家帶來幫助。。

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