SwipeRefreshLayout + ViewPager,仅限水平滚动?
我在我的应用程序中实现了SwipeRefreshLayout
和ViewPager
,但是有一个很大的麻烦:每当我要向左/向右滑动来切换页面时,滚动过于敏感。 向下轻扫一下也会触发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>
任何帮助将不胜感激,谢谢
我不确定你是否仍然有这个问题,但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
OnPageChangeListener
的SwipeRefreshLayout
上的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); } ...