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继续传递到该组件的滑动方法,然后可以在滑动方法中做一些操作,在滑动执行完成时可以让父组件的滑动恢复正常,这就是我在解决滑动冲突的思路,希望可以给大家带来帮助。。