SwipeRefreshLayout + ViewPager,仅限水平滚动?

我在我的应用程序中实现了SwipeRefreshLayoutViewPager ,但是有一个很大的麻烦:每当我要向左/向右滑动来切换页面时,滚动过于敏感。 向下轻扫一下也会触发SwipeRefreshLayout刷新。

我想设置水平滑动开始的限制,然后强制水平,直到刷卡结束。 换句话说,当手指水平移动时,我想取消垂直翻转。

这个问题只发生在ViewPager ,如果我向下滑动并触发SwipeRefreshLayout刷新function(显示条),然后水平移动我的手指,它仍然只允许垂直滑动。

我试图扩展ViewPager类,但它根本不工作:

 public class CustomViewPager extends ViewPager { public CustomViewPager(Context ctx, AttributeSet attrs) { super(ctx, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean in = super.onInterceptTouchEvent(ev); if (in) { getParent().requestDisallowInterceptTouchEvent(true); this.requestDisallowInterceptTouchEvent(true); } return false; } } 

布局xml:

 <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/viewTopic" android:layout_width="match_parent" android:layout_height="match_parent"> <com.myapp.listloader.foundation.CustomViewPager android:id="@+id/topicViewPager" android:layout_width="match_parent" android:layout_height="match_parent"/> </android.support.v4.widget.SwipeRefreshLayout> 

任何帮助将不胜感激,谢谢

Solutions Collecting From Web of "SwipeRefreshLayout + ViewPager,仅限水平滚动?"

我不确定你是否仍然有这个问题,但Google I / O应用程序iosched因此解决了这个问题:

  viewPager.addOnPageChangeListener( new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled( int position, float v, int i1 ) { } @Override public void onPageSelected( int position ) { } @Override public void onPageScrollStateChanged( int state ) { enableDisableSwipeRefresh( state == ViewPager.SCROLL_STATE_IDLE ); } } ); private void enableDisableSwipeRefresh(boolean enable) { if (swipeContainer != null) { swipeContainer.setEnabled(enable); } } 

我也使用了相同的,工作得很好。

编辑:使用addOnPageChangeListener()而不是setOnPageChangeListener()。

解决很简单,不扩展任何东西

 mPager.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mLayout.setEnabled(false); switch (event.getAction()) { case MotionEvent.ACTION_UP: mLayout.setEnabled(true); break; } return false; } }); 

像魅力一样工作

我遇到了你的问题。 自定义SwipeRefreshLayout将解决问题。

 public class CustomSwipeToRefresh extends SwipeRefreshLayout { private int mTouchSlop; private float mPrevX; public CustomSwipeToRefresh(Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPrevX = MotionEvent.obtain(event).getX(); break; case MotionEvent.ACTION_MOVE: final float eventX = event.getX(); float xDiff = Math.abs(eventX - mPrevX); if (xDiff > mTouchSlop) { return false; } } return super.onInterceptTouchEvent(event); } 

请参阅ref: 链接

我基于以前的答案,但发现这个工作好一点。 动作以ACTION_MOVE事件开始,以我的经验结束于ACTION_UP或ACTION_CANCEL。

 mViewPager.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: mSwipeRefreshLayout.setEnabled(false); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mSwipeRefreshLayout.setEnabled(true); break; } return false; } }); 

出于某种原因,只有他们才知道,支持库开发人员团队认为,即使在孩子明确要求事件所有权的情况下,也可以从SwipeRefreshLayout的子布局强制拦截所有垂直拖动事件。 他们唯一检查的是它的主子的垂直滚动状态为零(如果它的子是垂直滚动的)。 requestDisallowInterceptTouchEvent()方法已经被一个空的主体覆盖,并且(不那么)照亮的注释“Nope”。

解决这个问题最简单的方法就是将支持库中的类复制到项目中,并删除方法覆盖。 ViewGroup的实现使用内部状态来处理onInterceptTouchEvent() ,所以你不能简单地重写这个方法并重复它。 如果你真的想重写支持库的实现,那么你必须在调用requestDisallowInterceptTouchEvent()时设置一个自定义标志,并根据这个行为重写onInterceptTouchEvent()onTouchEvent() (或者可能破解canChildScrollUp() )行为。

nhasan的解决scheme有一个问题:

如果在SwipeRefreshLayout已经识别Pull-to-Reload但尚未调用通知callback的情况下SwipeRefreshLayout OnPageChangeListenerSwipeRefreshLayout上的setEnabled(false)调用的水平滑动,animation将消失,但SwipeRefreshLayout的内部状态一直保持“清爽”,因为没有通知callback被称为可以重置状态。 从用户angular度来看,这意味着由于所有的拉动手势都不被识别,所以“重新加载”不再起作用。

这里的问题是, disable(false)调用删除了微调器的animation,并且通知callback从该微调器的内部AnimationListener的onAnimationEnd方法被调用,该内部AnimationListener被设置为这样的顺序。

不可否认,我们的testing人员用最快的手指来挑起这种情况,但在现实的情况下,偶尔也会发生。

解决这个onInterceptTouchEvent方法是重写onInterceptTouchEvent中的onInterceptTouchEvent方法,如下所示:

 public class MySwipeRefreshLayout extends SwipeRefreshLayout { private boolean paused; public MySwipeRefreshLayout(Context context) { super(context); setColorScheme(); } public MySwipeRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); setColorScheme(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (paused) { return false; } else { return super.onInterceptTouchEvent(ev); } } public void setPaused(boolean paused) { this.paused = paused; } } 

在布局 – 文件中使用MySwipeRefreshLayout ,并将MySwipeRefreshLayout解决scheme中的代码更改为

 ... @Override public void onPageScrollStateChanged(int state) { swipeRefreshLayout.setPaused(state != ViewPager.SCROLL_STATE_IDLE); } ...