android - usar - Cómo deshabilitar el desplazamiento de RecyclerView, excepto mediante programación
recyclerview android studio example (6)
Tengo un RecyclerView
con un LinearLayoutManager
en orientación HORIZONTAL
. Cada elemento en él puede tener elementos interactivos (incluidos los ScrollView
verticales). ¿Hay alguna manera de hacer que el RecyclerView
ignore fácilmente cualquier intento del usuario de desplazar o lanzar el RecyclerView
horizontalmente sin interceptar eventos táctiles a los niños?
Estoy controlando programáticamente el desplazamiento del RecyclerView
que funciona muy bien hasta que el usuario lo arroja.
He intentado algo muy simple donde la idea es cuando llamo a smoothScrollToPosition en respuesta a algún evento, habilito el desplazamiento y deshabilito los eventos táctiles hasta que el desplazamiento se establece. Me gusta esto:
private class NoScrollHorizontalLayoutManager extends LinearLayoutManager {
ScrollingTouchInterceptor interceptor = new ScrollingTouchInterceptor();
protected boolean canScroll;
public NoScrollHorizontalLayoutManager(Context ctx) {
super(ctx, LinearLayoutManager.HORIZONTAL, false);
}
public RecyclerView.OnItemTouchListener getInterceptor() {
return interceptor;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
canScroll = true;
super.smoothScrollToPosition(recyclerView, state, position);
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if(state == RecyclerView.SCROLL_STATE_IDLE) {
canScroll = false;
}
}
@Override
public boolean canScrollHorizontally() {
return canScroll;
}
public class ScrollingTouchInterceptor implements RecyclerView.OnItemTouchListener {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return canScrollHorizontally();
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
}
Y úsalo así ...
NoScrollHorizontalLayoutManager layout = new NoScrollHorizontalLayoutManager(context);
recycler.setLayoutManager(layout);
recycler.addOnItemTouchListener(layout.getInterceptor());
que en realidad casi funciona ... pero aún puedo arruinar el desplazamiento programático tocando la pantalla cuando el desplazamiento suave está en movimiento. claramente me estoy perdiendo algo obvio o hay una manera mucho más inteligente de hacer esto.
ACTUALIZAR la solución que no es RecyclerView se encontró aquí: ¿Cómo deshabilitar la paginación deslizando el dedo en ViewPager pero aún así se puede deslizar programáticamente?
/**
* ViewPager that doesn''t allow swiping.
*/
public class NonSwipeableViewPager extends ViewPager {
public NonSwipeableViewPager(Context context) {
super(context);
}
public NonSwipeableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
}
Al invalidar onInterceptTouchEvent, se evita el comportamiento de detención al hacer clic.
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return false;
}
Lo primero, no creo que esto se pueda lograr de manera no programática.
Modo 1: simple: deshabilite la otra vista basada en el toque.
Si el usuario toca el padre, deshabilite el desplazamiento de las vistas secundarias. viceversa también
Pedazo de código para hacer esto.
recyclerView.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View p_v, MotionEvent p_event)
{
yourChildView.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
});
Forma 2: ya que tiene pequeños problemas en su implementación. Si lo publicas, alguien puede arreglar eso también.
Esto le da el efecto de continuidad.
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
recyclerView.smoothScrollToPosition(position);
return true;
} else if (action == MotionEvent.ACTION_UP) {
recyclerView.smoothScrollToPosition(position);
return true;
}
return false;
}
});
recyclerView.setNestedScrollingEnabled(false);
Para más información ver documentation .
android:nestedScrollingEnabled="false"
Haga lo anterior en el archivo xml, en el TAG RecyclerView.
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});