android - SwipeRefreshLayout+ViewPager, ¿limita el desplazamiento horizontal solamente?
android-viewpager gesture (6)
Basé esto en una respuesta anterior pero encontré que esto funcionaba un poco mejor. La moción comienza con un evento ACTION_MOVE y termina en ACTION_UP o ACTION_CANCEL en mi experiencia.
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;
}
});
Implementé SwipeRefreshLayout
y ViewPager
en mi aplicación, pero hay un gran problema: cada vez que voy a desplazarme hacia la izquierda / derecha para alternar entre las páginas, el desplazamiento es demasiado delicado. Un pequeño deslizamiento hacia abajo activará la actualización SwipeRefreshLayout
también.
Quiero establecer un límite para cuando se inicie el deslizamiento horizontal, luego forzarlo horizontalmente solo hasta que pase el deslizamiento. En otras palabras, quiero cancelar el desplazamiento vertical cuando el dedo se mueve horizontalmente.
Este problema solo ocurre en ViewPager
, si ViewPager
hacia abajo y se SwipeRefreshLayout
la función de refresco SwipeRefreshLayout
(se muestra la barra) y luego muevo mi dedo horizontalmente, todavía solo permite deslizamientos verticales.
Intenté extender la clase ViewPager
pero no funciona en absoluto:
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;
}
}
Layout 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>
Cualquier ayuda será apreciada, gracias
Hay un problema con la solución de nhasan:
Si el deslizamiento horizontal que desencadena la setEnabled(false)
en SwipeRefreshLayout
en OnPageChangeListener
ocurre cuando SwipeRefreshLayout
ya ha reconocido un Pull-to-Reload pero aún no ha llamado a la notificación de devolución de llamada, la animación desaparece pero el estado interno de SwipeRefreshLayout
se mantiene "refrescante" para siempre ya que no se llaman devoluciones de llamadas de notificación que podrían restablecer el estado. Desde la perspectiva del usuario, esto significa que Pull-to-Reload ya no funciona, ya que no se reconocen todos los gestos de extracción.
El problema aquí es que la llamada de disable(false)
elimina la animación de la ruleta y se llama a la devolución de llamada de notificación desde el método onAnimationEnd
de un AnimationListener interno para esa ruleta que está onAnimationEnd
de esa manera.
Fue necesario que nuestro examinador con los dedos más rápidos provocara esta situación, pero también puede suceder de vez en cuando en escenarios realistas.
Una solución para solucionar esto es anular el método SwipeRefreshLayout
en SwipeRefreshLayout
siguiente manera:
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;
}
}
Use MySwipeRefreshLayout
en su Diseño - Archivo y cambie el código en la solución de mhasan a
...
@Override
public void onPageScrollStateChanged(int state) {
swipeRefreshLayout.setPaused(state != ViewPager.SCROLL_STATE_IDLE);
}
...
He encontrado tu problema. Personalizar SwipeRefreshLayout resolvería el problema.
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);
}
Ver la referencia: link
No estoy seguro de si todavía tiene este problema, pero la aplicación Google I / O apilada resuelve este problema de la siguiente manera:
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);
}
}
He usado el mismo y funciona bastante bien.
EDITAR: Use addOnPageChangeListener () en lugar de setOnPageChangeListener ().
Por alguna razón que solo ellos conocen mejor, el equipo de desarrolladores de la biblioteca de soporte consideró oportuno interceptar con fuerza todos los eventos de movimiento vertical de arrastre del diseño infantil de SwipeRefreshLayout
, incluso cuando un niño solicita específicamente la propiedad del evento. Lo único que comprueban es que el estado de desplazamiento vertical de su hijo principal está en cero (en el caso de que su hijo sea verticalmente desplazable). El método requestDisallowInterceptTouchEvent()
ha sido anulado con un cuerpo vacío, y el (no tan) esclarecedor comentario "Nope".
La forma más sencilla de resolver este problema sería copiar la clase de la biblioteca de soporte en su proyecto y eliminar la anulación del método. La implementación de ViewGroup
usa un estado interno para manejar onInterceptTouchEvent()
, por lo que no puede simplemente sobrescribir el método nuevamente y duplicarlo. Si realmente desea anular la implementación de la biblioteca de soporte, deberá configurar un indicador personalizado en las llamadas a requestDisallowInterceptTouchEvent()
y anular el onInterceptTouchEvent()
y onTouchEvent()
(o posiblemente hackear el canChildScrollUp()
) en función de eso.
Resuelto de manera muy simple sin extender nada
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;
}
});
trabajar como un encanto