J'ai une feuille inférieure imbriquée dans une autre feuille inférieure (FrameLayouts
utilisant le comportement de disposition BottomSheet
)
J'ai également quelques "vues d'aperçu" (FrameLayouts
) auxquelles des écouteurs de clic sont attachés, pour développer respectivement la ou les feuilles inférieures, lorsque vous cliquez dessus.
Ainsi, l'application dispose essentiellement de 3 écrans principaux. Le `` conteneur principal '', puis la première `` feuille inférieure '', qui peut être développée en plein écran, puis au bas de la première feuille inférieure, est la deuxième feuille inférieure, qui peut également être développée en plein écran.
Problème:
Lorsque j'ajoute un RecyclerView
à la vue 'conteneur' de la feuille inférieure imbriquée, le glissement cesse de fonctionner pour la deuxième vue d'aperçu (feuille 2 d'aperçu). Si je supprime la vue d'aperçu ClickListener
ou la RecyclerView
, les choses semblent fonctionner parfaitement bien.
Résultat désiré:
Les deux feuilles inférieures doivent rester déplaçables et les vues d'aperçu doivent pouvoir être cliquées pour développer leur feuille inférieure parent. La feuille inférieure doit répondre aux parchemins imbriqués comme elle le ferait normalement.
J'ai essayé de supprimer le ClickListener
et d'utiliser des gestes tactiles à la place, mais rien de ce que j'ai essayé ne semble aider.
J'utilise v25.3.1
de la bibliothèque de support de conception, et je peux reproduire ce problème sur un Galaxy S4 exécutant le stock 4.4.4 et un Nexus 6P exécutant le stock 7.1.2. (Je n'ai pas d'autre appareil disponible).
J'ai également créé un projet de test sur github pour toute personne intéressée à y regarder de plus près: https://github.com/timusus/bottomsheet-test
Voici quelques captures d'écran illustrant la mise en page:
La structure de mise en page ressemble à ceci (du code a été omis pour plus de clarté):
<CoordinatorLayout>
<FrameLayout
Android:id="@+id/mainContainer"
Android:layout_height="match_parent"/>
<FrameLayout
Android:id="@+id/sheet1"
Android:layout_height="match_parent"
app:layout_behavior="CustomBottomSheetBehavior"
app:behavior_peekHeight="64dp">
<FrameLayout
Android:id="@+id/sheet1Container"
Android:layout_height="match_parent"/>
<CoordinatorLayout>
<FrameLayout
Android:id="@+id/sheet2
Android:layout_height="match_parent"
app:layout_behavior="CustomBottomSheetBehavior"
app:behavior_peekHeight="64dp">
<FrameLayout
Android:id="@+id/sheet2Container"
Android:layout_height="match_parent">
<!-- Problematic RecyclerView -->
<RecyclerView
Android:layout_height="match_parent"/>
</FrameLayout>
<!-- Problematic Click Listener on this view -->
<FrameLayout
Android:id="@+id/sheet2PeekView"
Android:layout_height=64dp"/>
</FrameLayout>
</CoordinatorLayout>
<FrameLayout
Android:id="@+id/sheet1PeekView"
Android:layout_height=64dp"/>
</FrameLayout>
</CoordinatorLayout/>
CustomBottomSheetBehavior
n'est qu'une simple sous-classe de BottomSheetBehavior
qui empêche la première feuille d'intercepter des événements tactiles si la deuxième feuille est développée ou déplacée. Cela permet à la deuxième feuille d'être glissée de "développé" à "réduit" sans également réduire la première feuille.
public class CustomBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
private boolean allowDragging = true;
public void setAllowDragging(boolean allowDragging) {
this.allowDragging = allowDragging;
}
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
if (!allowDragging) {
return false;
}
return super.onInterceptTouchEvent(parent, child, event);
}
}
Je ne pense pas que la personnalisation de BottomSheetBehavior
soit pertinente pour ce problème, mais pour être complet, voici comment elle est utilisée:
FrameLayout sheet1 = (FrameLayout) findViewById(R.id.sheet1);
bottomSheetBehavior1 = (CustomBottomSheetBehavior) BottomSheetBehavior.from(sheet1);
FrameLayout sheet2 = (FrameLayout) findViewById(R.id.sheet2);
bottomSheetBehavior2 = (CustomBottomSheetBehavior) BottomSheetBehavior.from(sheet2);
bottomSheetBehavior2.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
//If the second sheet is expanded or dragging, don't allow the first sheet to respond to touch events.
if (newState == BottomSheetBehavior.STATE_EXPANDED || newState == BottomSheetBehavior.STATE_DRAGGING) {
bottomSheetBehavior1.setAllowDragging(false);
} else {
bottomSheetBehavior1.setAllowDragging(true);
}
}
Je n'arrive pas à comprendre si cela a à voir avec le onInterceptTouchEvent
du BottomSheet
, la gestion du défilement imbriqué du RecyclerView
, View.ClickListener
voler des événements tactiles, une combinaison des éléments ci-dessus ou autre chose.
Toute aide serait très appréciée.
[~ # ~] fixe [~ # ~]
Je n'arrive pas à comprendre si cela a à voir avec onInterceptTouchEvent de la feuille de fond, la gestion du défilement imbriqué de RecyclerView interne, View.ClickListener volant des événements tactiles, une combinaison des éléments ci-dessus ou autre chose.
Il s'agit d'une combinaison des éléments ci-dessus CustomBottomSheetBehavior et View.ClickListener
Le problème était bottomSheetBehavior1 prend un événement de glissement lorsque getSheet2PeekView fait glisser pour détecter le toucher événement sur getSheet2PeekView et définissez bottomSheetBehavior1 en faisant glisser false
et bottomSheetBehavior2 true
Mettez ce code et votre problème est résolu.
findViewById(getSheet2PeekViewResId()).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e(TAG, "onTouch: ");
bottomSheetBehavior1.setAllowDragging(false);
bottomSheetBehavior2.setAllowDragging(true);
return false;
}
});
Également créé Pull Request à votre référentiel avec des modifications pleinement fonctionnelles.