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繼續傳遞到該組件的滑動方法,然後可以在滑動方法中做一些操作,在滑動執行完成時可以讓父組件的滑動恢復正常,這就是我在解決滑動衝突的思路,希望可以給大家帶來幫助。。