J'ai une RecyclerView
avec une LinearLayoutManager
en orientation HORIZONTAL
. Chaque élément de celui-ci peut avoir des éléments interactifs (y compris ScrollView
s vertical). Existe-t-il un moyen de faire en sorte que RecyclerView
ignore toutes les tentatives de l'utilisateur de faire défiler ou de lancer la RecyclerView
horizontalement sans intercepter les événements tactiles des enfants?
Je contrôle par programme le parchemin de la RecyclerView
qui fonctionne très bien jusqu'à ce que l'utilisateur le lance.
J'ai essayé quelque chose de très simple: lorsque j'appelle smoothScrollToPosition en réponse à un événement, j'active le défilement et désactive les événements tactiles jusqu'à ce que le défilement soit réglé. Comme ça:
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) {
}
}
}
Et utilisez-le comme ça ..
NoScrollHorizontalLayoutManager layout = new NoScrollHorizontalLayoutManager(context);
recycler.setLayoutManager(layout);
recycler.addOnItemTouchListener(layout.getInterceptor());
ce qui en fait presque _ fonctionne ... mais je peux toujours bousiller le défilement par programmation en touchant l'écran lorsque le défilement régulier est en mouvement Clairement, il me manque quelque chose d’évident ou il existe un moyen beaucoup plus intelligent de le faire.
UPDATE la solution non-RecyclerView a été trouvée ici: Comment désactiver la pagination en balayant avec le doigt dans ViewPager tout en pouvant effectuer un balayage par programme?
/**
* 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;
}
}
En remplaçant onInterceptTouchEvent, vous évitez le comportement d'arrêt des clics.
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return false;
}
Tout d’abord, je ne pense pas que cela soit réalisable de manière non programmatique.
Way 1: Simple - Désactive l’autre vue en fonction du toucher.
Si l'utilisateur touche le parent, désactive le défilement des vues enfants. vice versa aussi
Morceau de code pour le faire
recyclerView.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View p_v, MotionEvent p_event)
{
yourChildView.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
});
Voie 2: Depuis que vous rencontrez de petits problèmes dans votre mise en œuvre. Si vous le publiez, quelqu'un pourra également résoudre ce problème.
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
Cela donne l'effet de continuité.
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;
}
});