android多种滑动冲突的解决方案

android多种滑动冲突的解决方案,第1张

概述一、前言Android中解决滑动的方案有2种:外部拦截法和内部拦截法。滑动冲突也存在2种场景:横竖滑动冲突、同向滑动冲突。

一、前言

AndroID 中解决滑动的方案有2种:外部拦截法 和内部拦截法。

滑动冲突也存在2种场景: 横竖滑动冲突、同向滑动冲突。

所以我就写了4个例子来学习如何解决滑动冲突的,这四个例子分别为: 外部拦截法解决横竖冲突、外部拦截法解决同向冲突、内部拦截法解决横竖冲突、内部拦截法解决同向冲突。

先上效果图:

二、实战

1、外部拦截法,解决横竖冲突

思路是,重写父控件的onIntercepttouchEvent方法,然后根据具体的需求,来决定父控件是否拦截事件。如果拦截返回返回true,不拦截返回false。如果父控件拦截了事件,则在父控件的ontouchEvent进行相应的事件处理。

我的这个例子,是一个横向滑动的VIEwGroup里面包含了3个竖向滑动的ListVIEw。下面我附上代码,HorizontalEx.Java:

/** * Created by blueBerry on 2016/6/20. * * 解决交错的滑动冲突 * * 外部拦截法 */public class HorizontalEx extends VIEwGroup { private static final String TAG = "HorizontalEx"; private boolean isFirsttouch = true; private int childindex; private int childCount; private int lastXIntercept,lastYIntercept,lastX,lastY; private Scroller mScroller; private VeLocityTracker mVeLocityTracker; public HorizontalEx(Context context) {  super(context);  init(); } public HorizontalEx(Context context,AttributeSet attrs) {  super(context,attrs);  init(); } public HorizontalEx(Context context,AttributeSet attrs,int defStyleAttr) {  super(context,attrs,defStyleAttr);  init(); } private voID init() {  mScroller = new Scroller(getContext());  mVeLocityTracker = VeLocityTracker.obtain(); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) {  int wIDth = MeasureSpec.getSize(wIDthMeasureSpec);  int height = MeasureSpec.getSize(heightmeasureSpec);  int wIDthMode = MeasureSpec.getMode(wIDthMeasureSpec);  int heightmode = MeasureSpec.getMode(heightmeasureSpec);  childCount = getChildCount();  measureChildren(wIDthMeasureSpec,heightmeasureSpec);  if (childCount == 0) {   setMeasuredDimension(0,0);  } else if (wIDthMode == MeasureSpec.AT_MOST && heightmode == MeasureSpec.AT_MOST) {   wIDth = childCount * getChildAt(0).getMeasureDWIDth();   height = getChildAt(0).getMeasuredHeight();   setMeasuredDimension(wIDth,height);  } else if (wIDthMode == MeasureSpec.AT_MOST) {   wIDth = childCount * getChildAt(0).getMeasureDWIDth();   setMeasuredDimension(wIDth,height);  } else {   height = getChildAt(0).getMeasuredHeight();   setMeasuredDimension(wIDth,height);  } } @OverrIDe protected voID onLayout(boolean changed,int l,int t,int r,int b) {  int left = 0;  for (int i = 0; i < getChildCount(); i++) {   final VIEw child = getChildAt(i);   child.layout(left + l,t,r + left,b);   left += child.getMeasureDWIDth();  } } /**  * 拦截事件  * @param ev  * @return  */ @OverrIDe public boolean onIntercepttouchEvent(MotionEvent ev) {  boolean intercepted = false;  int x = (int) ev.getX();  int y = (int) ev.getY();  switch (ev.getAction()) {   /*如果拦截了Down事件,则子类不会拿到这个事件序列*/   case MotionEvent.ACTION_DOWN:    lastXIntercept = x;    lastYIntercept = y;    intercepted = false;    if (!mScroller.isFinished()) {     mScroller.abortAnimation();     intercepted = true;    }    break;   case MotionEvent.ACTION_MOVE:    final int deltaX = x - lastXIntercept;    final int deltaY = y - lastYIntercept;    /*根据条件判断是否拦截该事件*/    if (Math.abs(deltaX) > Math.abs(deltaY)) {     intercepted = true;    } else {     intercepted = false;    }    break;   case MotionEvent.ACTION_UP:    intercepted = false;    break;  }  lastXIntercept = x;  lastYIntercept = y;  return intercepted; } @OverrIDe public boolean ontouchEvent(MotionEvent event) {  int x = (int) event.getX();  int y = (int) event.getY();  mVeLocityTracker.addMovement(event);  VIEwConfiguration configuration = VIEwConfiguration.get(getContext());  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    if (!mScroller.isFinished()) {     mScroller.abortAnimation();    }    break;   case MotionEvent.ACTION_MOVE:    /*因为这里父控件拿不到Down事件,所以使用一个布尔值,     当事件第一次来到父控件时,对lastX,lastY赋值*/    if (isFirsttouch) {     lastX = x;     lastY = y;     isFirsttouch = false;    }    final int deltaX = x - lastX;    scrollBy(-deltaX,0);    break;   case MotionEvent.ACTION_UP:    int scrollX = getScrollX();    final int chilDWIDth = getChildAt(0).getWIDth();    mVeLocityTracker.computeCurrentVeLocity(1000,configuration.getScaledMaximumFlingVeLocity());    float xVeLocity = mVeLocityTracker.getXVeLocity();    if (Math.abs(xVeLocity) > configuration.getScaledMinimumFlingVeLocity()) {     childindex = xVeLocity < 0 ? childindex + 1 : childindex - 1;    } else {     childindex = (scrollX + chilDWIDth / 2) / chilDWIDth;    }    childindex = Math.min(getChildCount() - 1,Math.max(childindex,0));    smoothScrollBy(childindex * chilDWIDth - scrollX,0);    mVeLocityTracker.clear();    isFirsttouch = true;    break;  }  lastX = x;  lastY = y;  return true; } voID smoothScrollBy(int dx,int dy) {  mScroller.startScroll(getScrollX(),getScrollY(),dx,dy,500);  invalIDate(); } @OverrIDe public voID computeScroll() {  if (mScroller.computeScrollOffset()) {   scrollTo(mScroller.getCurrX(),mScroller.getCurrY());   invalIDate();  } } @OverrIDe protected voID onDetachedFromWindow() {  super.onDetachedFromWindow();  mVeLocityTracker.recycle(); }}

调用代码:

@OverrIDe public voID showOutHVData(List<String> data1,List<String> data2,List<String> data3) {  ListVIEw ListVIEw1 = new ListVIEw(getContext());  ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(getContext(),androID.R.layout.simple_List_item_1,data1);  ListVIEw1.setAdapter(adapter1);  ListVIEw ListVIEw2 = new ListVIEw(getContext());  ArrayAdapter<String> adapter2 = new ArrayAdapter<String>(getContext(),data2);  ListVIEw2.setAdapter(adapter2);  ListVIEw ListVIEw3 = new ListVIEw(getContext());  ArrayAdapter<String> adapter3 = new ArrayAdapter<String>(getContext(),data3);  ListVIEw3.setAdapter(adapter3);  VIEwGroup.LayoutParams params    = new VIEwGroup.LayoutParams(VIEwGroup.LayoutParams.MATCH_PARENT,VIEwGroup.LayoutParams.MATCH_PARENT);  mHorizontalEx.addVIEw(ListVIEw1,params);  mHorizontalEx.addVIEw(ListVIEw2,params);  mHorizontalEx.addVIEw(ListVIEw3,params); }

其实外部拦截的主要思想都在于对onIntercepttouchEvent的重写。

@OverrIDe public boolean onIntercepttouchEvent(MotionEvent ev) {  boolean intercepted = false;  int x = (int) ev.getX();  int y = (int) ev.getY();  switch (ev.getAction()) {   /*如果拦截了Down事件,则子类不会拿到这个事件序列*/   case MotionEvent.ACTION_DOWN:    lastXIntercept = x;    lastYIntercept = y;    intercepted = false;    if (!mScroller.isFinished()) {     mScroller.abortAnimation();     intercepted = true;    }    break;   case MotionEvent.ACTION_MOVE:    final int deltaX = x - lastXIntercept;    final int deltaY = y - lastYIntercept;    /*根据条件判断是否拦截该事件*/    if (Math.abs(deltaX) > Math.abs(deltaY)) {     intercepted = true;    } else {     intercepted = false;    }    break;   case MotionEvent.ACTION_UP:    intercepted = false;    break;  }  lastXIntercept = x;  lastYIntercept = y;  return intercepted; }

这几乎是一个实现外部拦截事件的模板,这里一定不要在ACTION_DOWN 中返回 true,否则会让子VIEw没有机会得到事件,因为如果在ACTION_DOWN的时候返回了 true,同一个事件序列VIEwGroup的disPatchtouchEvent就不会在调用onIntercepttouchEvent方法了。

还有就是 在ACTION_UP中返回false,因为如果父控件拦截了ACTION_UP,那么子VIEw将得不到UP事件,那么将会影响子VIEw的 Onclick方法等。但这对父控件是没有影响的,因为如果是父控件子ACITON_MOVE中 就拦截了事件,他们UP事件必定也会交给它处理,因为有那么一条定律叫做:父控件一但拦截了事件,那么同一个事件序列的所有事件都将交给他处理。这条结论在我的上一篇文章中已经分析过。

最后就是在 ACTION_MOVE中根据需求决定是否拦截。

2、内部拦截法,解决横竖冲突

内部拦截主要依赖于父控件的 requestdisallowIntercepttouchEvent方法,关于这个方法我的上篇文章其实已经分析过。他设置父控件的一个标志(FLAG_disALLOW_INTERCEPT)

这个标志可以决定父控件是否拦截事件,如果设置了这个标志则不拦截,如果没设这个标志,它就会调用父控件的onIntercepttouchEvent()来询问父控件是否拦截。但这个标志对Down事件无效。

可以参考一下源码:   

 // Handle an initial down.   if (actionMasked == MotionEvent.ACTION_DOWN) {    // Throw away all prevIoUs state when starting a new touch gesture.    // The framework may have dropped the up or cancel event for the prevIoUs gesture    // due to an app switch,ANR,or some other state change.    cancelAndCleartouchTargets(ev);    //清楚标志    resettouchState();   }   // Check for interception.   final boolean intercepted;   if (actionMasked == MotionEvent.ACTION_DOWN     || mFirsttouchTarget != null) {     //标志    final boolean disallowIntercept = (mGroupFlags & FLAG_disALLOW_INTERCEPT) != 0;    if (!disallowIntercept) {     intercepted = onIntercepttouchEvent(ev);     ev.setAction(action); // restore action in case it was changed    } else {     intercepted = false;    }   } else {    // There are no touch targets and this action is not an initial down    // so this vIEw group continues to intercept touches.    intercepted = true;   }

那么我们如果想使用 内部拦截法拦截事件。

第一步:

a、我们要重写父控件的onIntercepttouchEvent,在ACTION_DOWN的时候返回false,负责的话子VIEw调用requestdisallowIntercepttouchEvent也将无能为力。

b、还有就是其他事件的话都返回true,这样就把能否拦截事件的权利交给了子VIEw。

第二步:

在子VIEw的dispatchtouchEvent中 来决定是否让父控件拦截事件。

a. 先要在MotionEvent.ACTION_DOWN:的时候使用mHorizontalEx2.requestdisallowIntercepttouchEvent(true);,负责的话,下一个事件到来时,就交给父控件了。

b. 然后在MotionEvent.ACTION_MOVE: 根据业务逻辑决定是否调用mHorizontalEx2.requestdisallowIntercepttouchEvent(false);来决定父控件是否拦截事件。

上代码HorizontalEx2.java:

/** * Created by blueBerry on 2016/6/20. * 内部拦截 * 和 ListVIEwEx配合使用 */public class HorizontalEx2 extends VIEwGroup { private int lastX,lastY; private int childindex; private Scroller mScroller; private VeLocityTracker mVeLocityTracker; public HorizontalEx2(Context context) {  super(context);  init(); } public HorizontalEx2(Context context,attrs);  init(); } public HorizontalEx2(Context context,int heightmeasureSpec) {  int wIDth = MeasureSpec.getSize(wIDthMeasureSpec);  int wIDthMode = MeasureSpec.getMode(wIDthMeasureSpec);  int height = MeasureSpec.getSize(heightmeasureSpec);  int heightmode = MeasureSpec.getMode(heightmeasureSpec);  int childCount = getChildCount();  measureChildren(wIDthMeasureSpec,0);  } else if (wIDthMode == MeasureSpec.AT_MOST && heightmode == MeasureSpec.AT_MOST) {   height = getChildAt(0).getMeasuredHeight();   wIDth = childCount * getChildAt(0).getMeasureDWIDth();   setMeasuredDimension(wIDth,int b) {  int leftOffset = 0;  for (int i = 0; i < getChildCount(); i++) {   VIEw child = getChildAt(i);   child.layout(l + leftOffset,r + leftOffset,b);   leftOffset += child.getMeasureDWIDth();  } } /**  * 不拦截Down事件,其他一律拦截  * @param ev  * @return  */ @OverrIDe public boolean onIntercepttouchEvent(MotionEvent ev) {  if (ev.getAction() == MotionEvent.ACTION_DOWN) {   if (!mScroller.isFinished()) {    mScroller.abortAnimation();    return true;   }   return false;  } else {   return true;  } } private boolean isFirsttouch = true; @OverrIDe public boolean ontouchEvent(MotionEvent event) {  int x = (int) event.getX();  int y = (int) event.getY();  mVeLocityTracker.addMovement(event);  VIEwConfiguration configuration = VIEwConfiguration.get(getContext());  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    if (!mScroller.isFinished()) {     mScroller.abortAnimation();    }    break;   case MotionEvent.ACTION_MOVE:    if (isFirsttouch) {     isFirsttouch = false;     lastY = y;     lastX = x;    }    final int deltaX = x - lastX;    scrollBy(-deltaX,0);    break;   case MotionEvent.ACTION_UP:    isFirsttouch = true;    int scrollX = getScrollX();    mVeLocityTracker.computeCurrentVeLocity(1000,configuration.getScaledMaximumFlingVeLocity());    float mVeLocityX = mVeLocityTracker.getXVeLocity();    if (Math.abs(mVeLocityX) > configuration.getScaledMinimumFlingVeLocity()) {     childindex = mVeLocityX < 0 ? childindex + 1 : childindex - 1;    } else {     childindex = (scrollX + getChildAt(0).getWIDth() / 2) / getChildAt(0).getWIDth();    }    childindex = Math.min(getChildCount() - 1,Math.max(0,childindex));    smoothScrollBy(childindex*getChildAt(0).getWIDth()-scrollX,0);    mVeLocityTracker.clear();    break;  }  lastX = x;  lastY = y;  return true; } private voID smoothScrollBy(int dx,500);  invalIDate(); } @OverrIDe public voID computeScroll() {  if(mScroller.computeScrollOffset()){   scrollTo(mScroller.getCurrX(),mScroller.getCurrY());   postInvalIDate();  } } @OverrIDe protected voID onDetachedFromWindow() {  super.onDetachedFromWindow();  mVeLocityTracker.recycle(); }}

ListVIEwEx.java

/** * 内部拦截事件 */public class ListVIEwEx extends ListVIEw { private int lastXIntercepted,lastYIntercepted; private HorizontalEx2 mHorizontalEx2; public ListVIEwEx(Context context) {  super(context); } public ListVIEwEx(Context context,attrs); } public ListVIEwEx(Context context,defStyleAttr); } public HorizontalEx2 getmHorizontalEx2() {  return mHorizontalEx2; } public voID setmHorizontalEx2(HorizontalEx2 mHorizontalEx2) {  this.mHorizontalEx2 = mHorizontalEx2; } /**  * 使用 outter.requestdisallowIntercepttouchEvent();  * 来决定父控件是否对事件进行拦截  * @param ev  * @return  */ @OverrIDe public boolean dispatchtouchEvent(MotionEvent ev) {  int x = (int) ev.getX();  int y = (int) ev.getY();  switch (ev.getAction()) {   case MotionEvent.ACTION_DOWN:    mHorizontalEx2.requestdisallowIntercepttouchEvent(true);    break;   case MotionEvent.ACTION_MOVE:    final int deltaX = x-lastYIntercepted;    final int deltaY = y-lastYIntercepted;    if(Math.abs(deltaX)>Math.abs(deltaY)){     mHorizontalEx2.requestdisallowIntercepttouchEvent(false);    }    break;   case MotionEvent.ACTION_UP:    break;  }  lastXIntercepted = x;  lastYIntercepted = y;  return super.dispatchtouchEvent(ev); }}

调用代码:

 @OverrIDe public voID showInnerHVData(List<String> data1,List<String> data3) {  ListVIEwEx ListVIEw1 = new ListVIEwEx(getContext());  ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(getContext(),data1);  ListVIEw1.setAdapter(adapter1);  ListVIEw1.setmHorizontalEx2(mHorizontalEx2);  ListVIEwEx ListVIEw2 = new ListVIEwEx(getContext());  ArrayAdapter<String> adapter2 = new ArrayAdapter<String>(getContext(),data2);  ListVIEw2.setAdapter(adapter2);  ListVIEw2.setmHorizontalEx2(mHorizontalEx2);  ListVIEwEx ListVIEw3 = new ListVIEwEx(getContext());  ArrayAdapter<String> adapter3 = new ArrayAdapter<String>(getContext(),data3);  ListVIEw3.setAdapter(adapter3);  ListVIEw3.setmHorizontalEx2(mHorizontalEx2);  VIEwGroup.LayoutParams params    = new VIEwGroup.LayoutParams(VIEwGroup.LayoutParams.MATCH_PARENT,VIEwGroup.LayoutParams.MATCH_PARENT);  mHorizontalEx2.addVIEw(ListVIEw1,params);  mHorizontalEx2.addVIEw(ListVIEw2,params);  mHorizontalEx2.addVIEw(ListVIEw3,params); }

至此,2种拦截方法已经学习完毕,下面我们来学习如何解决同向滑动冲突。

其实和上面的2个例子思路是一样的,只是用来判断是否拦截的那块逻辑不同而已。

下面的例子,是一个下拉刷新的一个控件。

3、外部拦截 解决同向滑动冲突

RefreshLayoutBase.java

package com.blueBerry.sample.Widget.refresh;import androID.content.Context;import androID.graphics.color;import androID.util.AttributeSet;import androID.util.displayMetrics;import androID.util.Log;import androID.util.TypedValue;import androID.vIEw.MotionEvent;import androID.vIEw.VIEw;import androID.vIEw.VIEwConfiguration;import androID.vIEw.VIEwGroup;import androID.vIEw.WindowManager;import androID.Widget.Progressbar;import androID.Widget.Scroller;import androID.Widget.TextVIEw;import com.blueBerry.sample.R;/** *外部拦截(同向) * */public abstract class RefreshLayoutBase<T extends VIEw> extends VIEwGroup { private static final String TAG = "RefreshLayoutBase"; public static final int STATUS_LOADING = 1; public static final int STATUS_RELEASE_TO_REFRESH = 2; public static final int STATUS_PulL_TO_REFRESH = 3; public static final int STATUS_IDLE = 4; public static final int STATUS_LOAD_MORE =5; private static int SCRolL_DURATION =500; protected VIEwGroup mheadVIEw; protected VIEwGroup mFootVIEw; private T contentVIEw; private Progressbar headProgressbar; private TextVIEw headTv; private Progressbar footProgressbar; private TextVIEw foottv; private boolean isFisttouch = true; protected int currentStatus = STATUS_IDLE; private int mScreenWIDth; private int mScreenHeight; private int mLastXIntercepted; private int mLastYIntercepted; private int mLastX; private int mLastY; protected int mInitScrollY = 0; private int mtouchSlop; protected Scroller mScoller; private OnRefreshListener mOnRefreshListener; public RefreshLayoutBase(Context context) {  this(context,null); } public RefreshLayoutBase(Context context,AttributeSet attrs) {  this(context,0); } public RefreshLayoutBase(Context context,defStyleAttr);  getScreenSize();  initVIEw();  mScoller = new Scroller(context);  mtouchSlop = VIEwConfiguration.get(context).getScaledtouchSlop();  setpadding(0,0); } public voID setContentVIEw(T vIEw) {  addVIEw(vIEw,1); } public OnRefreshListener getonRefreshListener() {  return mOnRefreshListener; } public voID setonRefreshListener(OnRefreshListener mOnRefreshListener) {  this.mOnRefreshListener = mOnRefreshListener; } private voID initVIEw() {  setupheadVIEw();  setupFootVIEw(); } private voID getScreenSize() {  WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);  displayMetrics metrics = new displayMetrics();  wm.getDefaultdisplay().getMetrics(metrics);  mScreenWIDth = metrics.wIDthPixels;  mScreenHeight = metrics.heightPixels; } private int dp2px(int dp) {  WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);  displayMetrics metrics = new displayMetrics();  wm.getDefaultdisplay().getMetrics(metrics);  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,metrics); } /**  * 设置头布局  */ private voID setupheadVIEw() {  mheadVIEw = (VIEwGroup) VIEw.inflate(getContext(),R.layout.fresh_head_vIEw,null);  mheadVIEw.setBackgroundcolor(color.RED);  headProgressbar = (Progressbar) mheadVIEw.findVIEwByID(R.ID.head_progressbar);  headTv = (TextVIEw) mheadVIEw.findVIEwByID(R.ID.head_tv);  /*设置 实际高度为 1/4 ,但内容区域只有 100dP*/  VIEwGroup.LayoutParams layoutParams = new VIEwGroup.LayoutParams(LayoutParams.MATCH_PARENT,mScreenHeight / 4);  mheadVIEw.setLayoutParams(layoutParams);  mheadVIEw.setpadding(0,mScreenHeight / 4 - dp2px(100),0);  addVIEw(mheadVIEw); } /**  * 设置尾布局  */ private voID setupFootVIEw() {  mFootVIEw = (VIEwGroup) VIEw.inflate(getContext(),R.layout.fresh_foot_vIEw,null);  mFootVIEw.setBackgroundcolor(color.BLUE);  footProgressbar = (Progressbar) mFootVIEw.findVIEwByID(R.ID.fresh_foot_progressbar);  foottv = (TextVIEw) mFootVIEw.findVIEwByID(R.ID.fresh_foot_tv);  addVIEw(mFootVIEw); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) {  int wIDthSize = MeasureSpec.getSize(wIDthMeasureSpec);  int wIDthMode = MeasureSpec.getMode(wIDthMeasureSpec);  int height = MeasureSpec.getSize(heightmeasureSpec);  int heightmode = MeasureSpec.getMode(heightmeasureSpec);  int finalHeight = 0;  for (int i = 0; i < getChildCount(); i++) {   VIEw child = getChildAt(i);   measureChild(child,wIDthMeasureSpec,heightmeasureSpec);   finalHeight += child.getMeasuredHeight();  }  if (wIDthMode == MeasureSpec.AT_MOST && heightmode == MeasureSpec.AT_MOST) {   wIDthSize = getChildAt(0).getMeasureDWIDth();   setMeasuredDimension(wIDthSize,finalHeight);  } else if (wIDthMode == MeasureSpec.AT_MOST) {   wIDthSize = getChildAt(0).getMeasureDWIDth();   setMeasuredDimension(wIDthSize,height);  } else {   setMeasuredDimension(wIDthSize,finalHeight);  } } @OverrIDe protected voID onLayout(boolean changed,int b) {  int topOffset = 0;  for (int i = 0; i < getChildCount(); i++) {   VIEw child = getChildAt(i);   child.layout(getpaddingleft(),getpaddingtop() + topOffset,r,getpaddingtop() + child.getMeasuredHeight() + topOffset);   topOffset += child.getMeasuredHeight();  }  mInitScrollY = mheadVIEw.getMeasuredHeight() + getpaddingtop();  scrollTo(0,mInitScrollY); } @OverrIDe public boolean onIntercepttouchEvent(MotionEvent ev) {  boolean intercepted = false;  int x = (int) ev.getX();  int y = (int) ev.getY();  switch (ev.getAction()) {   case MotionEvent.ACTION_DOWN:    mLastXIntercepted = x;    mLastYIntercepted = y;    break;   case MotionEvent.ACTION_MOVE:    final int deltaY = x - mLastYIntercepted;    if (istop() && deltaY > 0 && Math.abs(deltaY) > mtouchSlop) {     /*下拉*/     intercepted = true;    }    break;   case MotionEvent.ACTION_UP:    break;  }  mLastXIntercepted = x;  mLastYIntercepted = y;  return intercepted; } private voID doRefresh() {  Log.i(TAG,"doRefresh: ");  if (currentStatus == STATUS_RELEASE_TO_REFRESH) {   mScoller.startScroll(0,mInitScrollY - getScrollY(),SCRolL_DURATION);   currentStatus = STATUS_IDLE;  } else if (currentStatus == STATUS_PulL_TO_REFRESH) {   mScoller.startScroll(0,0-getScrollY(),SCRolL_DURATION);   if (null != mOnRefreshListener) {    currentStatus = STATUS_LOADING;    mOnRefreshListener.refresh();   }  }  invalIDate(); } @OverrIDe public boolean ontouchEvent(MotionEvent event) {  int x = (int) event.getX();  int y = (int) event.getY();  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    if (!mScoller.isFinished()) {     mScoller.abortAnimation();    }    mLastX = x;    mLastY = y;    break;   case MotionEvent.ACTION_MOVE:    if (isFisttouch) {     isFisttouch = false;     mLastX = x;     mLastY = y;    }    final int deltaY = y - mLastY;    if (currentStatus != STATUS_LOADING) {     changeScrollY(deltaY);    }    break;   case MotionEvent.ACTION_UP:    isFisttouch = true;    doRefresh();    break;  }  mLastX = x;  mLastY = y;  return true; } private voID changeScrollY(int deltaY) {  Log.i(TAG,"changeScrollY: ");  int curY = getScrollY();  if (deltaY > 0) {   /*下拉*/   if (curY - deltaY > getpaddingtop()) {    scrollBy(0,-deltaY);   }  } else {   /*上拉*/   if (curY - deltaY <= mInitScrollY) {    scrollBy(0,-deltaY);   }  }  curY = getScrollY();  int slop = mInitScrollY / 2;  if (curY > 0 && curY <=slop) {   currentStatus = STATUS_PulL_TO_REFRESH;  } else if (curY > 0 && curY >= slop) {   currentStatus = STATUS_RELEASE_TO_REFRESH;  } } @OverrIDe public voID computeScroll() {  if (mScoller.computeScrollOffset()) {   scrollTo(mScoller.getCurrX(),mScoller.getCurrY());   postInvalIDate();  } } /**  * 加载完成调用这个方法  */ public voID refreshComplete() {  mScoller.startScroll(0,SCRolL_DURATION);  currentStatus = STATUS_IDLE;  invalIDate(); } /**  * 显示 Footer  */ public voID showFooter() {  if(currentStatus==STATUS_LOAD_MORE) return ;  currentStatus = STATUS_LOAD_MORE ;  mScoller.startScroll(0,mFootVIEw.getMeasuredHeight(),SCRolL_DURATION);  invalIDate(); } /**  * loadMore完成之后调用  */ public voID footerComplete() {  mScoller.startScroll(0,SCRolL_DURATION);  invalIDate();  currentStatus = STATUS_IDLE; } public interface OnRefreshListener {  voID refresh(); } abstract boolean istop(); abstract boolean isBottom();}

它是一个抽象类,需要编写子类继承istop()和 isBottom()方法。下面给出它的一个实现类:

package com.blueBerry.sample.Widget.refresh;import androID.content.Context;import androID.util.AttributeSet;import androID.Widget.AbsListVIEw;import androID.Widget.ListVIEw;/** * Created by blueBerry on 2016/6/21. * * RefreshLayoutBase 的一个实现类 */public class RefreshListVIEw extends RefreshLayoutBase<ListVIEw> { private static final String TAG = "RefreshListVIEw"; private ListVIEw ListVIEw; private OnLoadListener loadListener; public RefreshListVIEw(Context context) {  super(context); } public RefreshListVIEw(Context context,attrs); } public RefreshListVIEw(Context context,defStyleAttr); } public ListVIEw getListVIEw() {  return ListVIEw; } public voID setListVIEw(final ListVIEw ListVIEw) {  this.ListVIEw = ListVIEw;  setContentVIEw(ListVIEw);  this.ListVIEw.setonScrollListener(new AbsListVIEw.OnScrollListener() {   @OverrIDe   public voID onScrollStateChanged(AbsListVIEw vIEw,int scrollState) {   }   @OverrIDe   public voID onScroll(AbsListVIEw vIEw,int firstVisibleItem,int visibleItemCount,int totalitemCount) {    /*这里存在一个BUG: 当ListVIEw滑动到底部的时候,如果下拉也会出现footer    * 这是因为,暂时还没有想到如何判断是下拉还是上拉。    * 如果要解决此问题,我觉得应该重写ListVIEw 的ontouchEvent来判断手势方向    * 次模块主要解决竖向滑动冲突,故现将此问题放下。    * */    if (currentStatus == STATUS_IDLE      && getScrollY() <= mInitScrollY && isBottom()      ) {     showFooter();     if (null != loadListener) {      loadListener.onLoadMore();     }    }   }  }); } public OnLoadListener getLoadListener() {  return loadListener; } public voID setLoadListener(OnLoadListener loadListener) {  this.loadListener = loadListener; } @OverrIDe boolean istop() {  return ListVIEw.getFirstVisibleposition() == 0    && getScrollY() <= mheadVIEw.getMeasuredHeight(); } @OverrIDe boolean isBottom() {  return ListVIEw.getLastVisibleposition() == ListVIEw.getAdapter().getCount() - 1; } public interface OnLoadListener {  voID onLoadMore(); }}

4、内部拦截法解决同向滑动

同样是一个下拉刷新组件,因为实现原理都一样,所以这个写的比较随意些。主要还是如果解决滑动冲突。

RefreshLayoutBase2.java

package com.blueBerry.sample.Widget.refresh;import androID.content.Context;import androID.graphics.color;import androID.util.AttributeSet;import androID.util.Log;import androID.vIEw.MotionEvent;import androID.vIEw.VIEw;import androID.vIEw.VIEwGroup;import androID.Widget.ArrayAdapter;import androID.Widget.ListVIEw;import androID.Widget.Scroller;import com.blueBerry.sample.R;import java.util.ArrayList;import java.util.List;/** * Created by blueBerry on 2016/6/22. * 结合内部类 ListVIEEx * 内部拦截法,同向 */public class RefreshLayoutBase2 extends VIEwGroup { private static final String TAG = "RefreshLayoutBase2"; private static List<String> datas; static {  datas = new ArrayList<>();  for (int i = 0; i < 40; i++) {   datas.add("数据―" + i);  } } private VIEwGroup headVIEw; private ListVIEwEx lv; private int lastY; public int mInitScrollY; private Scroller mScroller; public RefreshLayoutBase2(Context context) {  this(context,null); } public RefreshLayoutBase2(Context context,0); } public RefreshLayoutBase2(Context context,defStyleAttr);  mScroller = new Scroller(context);  setupheadVIEw(context);  setupContentVIEw(context); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,finalHeight);  } } @OverrIDe protected voID onLayout(boolean changed,getpaddingtop() + child.getMeasuredHeight() + topOffset);   topOffset += child.getMeasuredHeight();  }  mInitScrollY = headVIEw.getMeasuredHeight() + getpaddingtop();  scrollTo(0,mInitScrollY); } /**  * 不拦截Down 其他一律拦截  * @param ev  * @return  */ @OverrIDe public boolean onIntercepttouchEvent(MotionEvent ev) {  if (ev.getAction() == MotionEvent.ACTION_DOWN) return false;  return true; } @OverrIDe public boolean ontouchEvent(MotionEvent event) {  int y = (int) event.getY();  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    break;   case MotionEvent.ACTION_MOVE:    final int deltaY = y-lastY;    Log.i(TAG,"ontouchEvent: deltaY: "+deltaY);    if (deltaY >= 0 && lv.istop() && getScrollY() - deltaY >=getpaddingtop()) {      scrollBy(0,-deltaY);    }    break;   case MotionEvent.ACTION_UP:    this.postDelayed(new Runnable() {     @OverrIDe     public voID run() {      mScroller.startScroll(0,mInitScrollY-getScrollY());      invalIDate();     }    },2000);    break;  }  lastY = y ;  return true; } private voID setupheadVIEw(Context context) {  headVIEw = (VIEwGroup) VIEw.inflate(context,null);  headVIEw.setBackgroundcolor(color.RED);  VIEwGroup.LayoutParams params = new VIEwGroup.LayoutParams(VIEwGroup.LayoutParams.MATCH_PARENT,300);  addVIEw(headVIEw,params); } public voID setupContentVIEw(Context context) {  lv = new ListVIEwEx(context,this);  lv.setBackgroundcolor(color.BLUE);  ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),datas);  lv.setAdapter(adapter);  addVIEw(lv,new VIEwGroup.LayoutParams(VIEwGroup.LayoutParams.MATCH_PARENT,VIEwGroup.LayoutParams.MATCH_PARENT)); } @OverrIDe public voID computeScroll() {  if(mScroller.computeScrollOffset()){   scrollTo(mScroller.getCurrX(),mScroller.getCurrY());   postInvalIDate();  } } public static class ListVIEwEx extends ListVIEw {  private RefreshLayoutBase2 outter;  public ListVIEwEx(Context context,RefreshLayoutBase2 outter) {   super(context);   this.outter = outter;  }  public ListVIEwEx(Context context,AttributeSet attrs) {   super(context,attrs);  }  public ListVIEwEx(Context context,int defStyleAttr) {   super(context,defStyleAttr);  }  /**   * 使用 outter.requestdisallowIntercepttouchEvent();   * 来决定父控件是否对事件进行拦截   * @param ev   * @return   */  @OverrIDe  public boolean dispatchtouchEvent(MotionEvent ev) {   switch (ev.getAction()) {    case MotionEvent.ACTION_DOWN:     outter.requestdisallowIntercepttouchEvent(true);     break;    case MotionEvent.ACTION_MOVE:     if ( istop() && outter.getScrollY() <= outter.mInitScrollY) {      outter.requestdisallowIntercepttouchEvent(false);     }     break;   }   return super.dispatchtouchEvent(ev);  }  public boolean istop() {   return getFirstVisibleposition() ==0;  } }}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的android多种滑动冲突的解决方案全部内容,希望文章能够帮你解决android多种滑动冲突的解决方案所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147027.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存