SwipeRefreshLayout + ViewPager, ограничьте только горизонтальную прокрутку?
я реализовал SwipeRefreshLayout
и ViewPager
в моем приложении, но есть большая проблема: всякий раз, когда я собираюсь провести влево / вправо, чтобы переключаться между страницами прокрутка слишком чувствительна. Немного проведите пальцем вниз вызовет SwipeRefreshLayout
обновить тоже.
Я хочу установить ограничение на то, когда начинается горизонтальный свайп, а затем принудительно горизонтально только до тех пор, пока свайп не закончится. Другими словами, Я хочу отменить вертикальное переключение, когда палец движется горизонтально.
эта проблема возникает только на ViewPager
, Если я проведите пальцем вниз и SwipeRefreshLayout
функция обновления запускается (отображается панель), а затем я перемещаю палец по горизонтали, он по-прежнему позволяет только вертикальные пойло.
Я пытался расширить 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>
любая помощь будет оценили, спасибо
6 ответов:
Я не уверен, если у вас все еще есть эта проблема, но 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); } }
я использовал то же самое и работает довольно хорошо.
EDIT: используйте 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); }
посмотреть код: ссылке
Я основал это на предыдущем ответе, но нашел, что это работает немного лучше. Движение начинается с события 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()
метод был переопределен с пустым телом, и (не так) освещения комментарий "Нет".самый простой способ решить эту проблему было бы просто скопировать класс из библиотеки в свой проект и удалить переопределение метода.
ViewGroup
реализация использует внутреннее состояние для обработкиonInterceptTouchEvent()
, поэтому вы не можете просто переопределить метод и дублируем его. Если вы действительно хотите переопределить реализация библиотеки поддержки, то вам придется настроить пользовательский флаг при вызовахrequestDisallowInterceptTouchEvent()
и переопределитьonInterceptTouchEvent()
иonTouchEvent()
(или, возможно, взломатьcanChildScrollUp()
) поведение, основанное на этом.
есть одна проблема с решением nhasan:
если горизонтальный свайп, который вызывает
setEnabled(false)
вызов наSwipeRefreshLayout
наOnPageChangeListener
происходит, когдаSwipeRefreshLayout
уже распознал Pull-to-Reload, но еще не вызвал обратный вызов уведомления, анимация исчезает, но внутреннее состояниеSwipeRefreshLayout
остается на "обновление" навсегда, так как не вызываются обратные вызовы уведомлений, которые могут сбросить состояние. С точки зрения пользователя это означает, что Pull-to-Reload больше не работает, так как все жесты вытягивания не распознаются.проблема здесь в том, что
disable(false)
вызов удаляет анимацию блесны и уведомление обратного вызова вызывается изonAnimationEnd
метод внутреннего AnimationListener для того прядильщика, который установлен не в порядке таким образом.по общему признанию, наш тестер с самыми быстрыми пальцами, чтобы спровоцировать эту ситуацию, но это может произойти время от времени в реалистичных сценариях, как что ж.
решение, чтобы исправить это, чтобы переопределить
onInterceptTouchEvent
методSwipeRefreshLayout
следующим образом: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
в вашем макете-файле и измените код в решении mhasan на... @Override public void onPageScrollStateChanged(int state) { swipeRefreshLayout.setPaused(state != ViewPager.SCROLL_STATE_IDLE); } ...