web-dev-qa-db-fra.com

Utilisation de BottomSheetBehavior avec un coordinateur interne

La bibliothèque de support de conception v. 23.2 A introduit BottomSheetBehavior, qui permet aux enfants d'un coordinateur d'agir comme des feuilles inférieures (vues déplaçables depuis le bas de l'écran).

Ce que je voudrais faire, c'est d'avoir, comme vue de bas de page , la vue suivante (le coordinateur typique + les choses qui se réduisent):

<CoordinatorLayout
    app:layout_behavior=“@string/bottom_sheet_behavior”>

   <AppBarLayout>
        <CollapsingToolbarLayout>
           <ImageView />
        </CollapsingToolbarLayout>
    </AppBarLayout>

    <NestedScrollView>
        <LinearLayout>
            < Content ... />
        </LinearLayout>
    </NestedScrollView>

</CoordinatorLayout>

Malheureusement, les vues de la feuille inférieure doivent implémenter le défilement imbriqué, sinon elles n'obtiendront pas d'événements de défilement. Si vous essayez avec une activité principale, puis chargez cette vue en tant que feuille inférieure, vous verrez que les événements de défilement n'agissent que sur la "feuille" de papier, avec un comportement étrange, comme vous pouvez le voir si vous continuez à lire.

Je suis sûr que cela peut être géré en sous-classant CoordinatorLayout, ou mieux encore en sous-classant BottomSheetBehavior. Avez-vous un indice?

Quelques idées

  • requestDisallowInterceptTouchEvent() doit être utilisé pour voler des événements au parent dans certaines conditions:

    • lorsque l'offset AppBarLayout est> 0
    • lorsque l'offset AppBarLayout est == 0, mais nous faisons défiler vers le haut (pensez-y une seconde et vous verrez)
  • la première condition peut être obtenue en définissant un OnOffsetChanged dans la barre d'application interne;

  • la seconde nécessite une gestion des événements, par exemple:

    switch (MotionEventCompat.getActionMasked(event)) {
        case MotionEvent.ACTION_DOWN:
            startY = event.getY();
            lastY = startY;
            userIsScrollingUp = false;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            userIsScrollingUp = false;
            break;
        case MotionEvent.ACTION_MOVE:
            lastY = event.getY();
            float yDeltaTotal = startY - lastY;
            if (yDeltaTotal > touchSlop) { // Moving the finger up.
                userIsScrollingUp = true;
            }
            break;
    }
    

Problèmes

Inutile de dire que je ne peux pas faire fonctionner ça maintenant. Je ne suis pas en mesure d'attraper les événements lorsque les conditions sont remplies, et de ne pas les attraper dans d'autres cas. Dans l'image ci-dessous, vous pouvez voir ce qui se passe avec un coordinateur standard.

  • La feuille est ignorée si vous faites défiler vers le bas sur la barre d'applications, mais pas si vous faites défiler vers le bas le contenu imbriqué. Il semble que les événements de défilement imbriqués ne se propagent pas au comportement du coordinateur;

  • Il y a également un problème avec la barre d'applications interne: le contenu du défilement imbriqué ne suit pas la barre d'applications lorsqu'elle est réduite.

enter image description here

J'ai configuré un exemple de projet sur github qui montre ces problèmes.

Pour être clair, le comportement souhaité est:

  • Comportement correct des barres d'applications/vues de défilement à l'intérieur de la feuille;

  • Lorsque la feuille est développée, elle peut s'effondrer lors du défilement vers le bas, mais uniquement si la barre d'application interne est également entièrement développée . À l'heure actuelle, il s'effondre sans égard à l'état de la barre d'applications, et uniquement si vous faites glisser la barre d'applications;

  • Lorsque la feuille est réduite, les gestes de défilement vers le haut la développent (sans effet sur la barre d’applications interne).

Un exemple de l'application contacts (qui n'utilise probablement pas BottomSheetBehavior, mais c'est ce que je veux):

enter image description here

54
natario

J'ai finalement publié mon implémentation. Trouvez-le sur Github ou directement depuis jcenter:

compile 'com.otaliastudios:bottomsheetcoordinatorlayout:1.0.0’

Tout ce que vous avez à faire est d'utiliser BottomSheetCoordinatorLayout comme vue racine de votre feuille inférieure. Il se gonflera automatiquement un comportement de travail, alors ne vous inquiétez pas.

Je l'utilise depuis longtemps et cela ne devrait pas avoir de problèmes de défilement, prend en charge le glissement sur l'ABL, etc.

5
natario

Je viens de suivre la façon dont vous avez posé la question ci-dessus et de trouver une solution qui pourrait nécessiter plus d'explications.S'il vous plaît suivez votre exemple de code et intégrez la partie supplémentaire dans votre xml pour le faire se comporter comme le comportement BottomSheeet

<CoordinatorLayout>
   <AppBarLayout>
        <Toolbar
            app:layout_collapseMode="pin">
        </Toolbar>
    </AppBarLayout>
    <NestedScrollView
         app:layout_behavior=“@string/bottom_sheet_behavior” >
        <include layout="@layout/items" />
    </NestedScrollView>

    <!-- Bottom Sheet -->

     <BottomSheetCoordinatorLayout>
        <AppBarLayout
            <CollapsingToolbarLayout">
             <ImageView />
                <Toolbar />
            </CollapsingToolbarLayout>
        </AppBarLayout>
        <NestedScrollView">
            <include layout="@layout/items" />
        </NestedScrollView>
    </BottomSheetCoordinatorLayout>
</CoordinatorLayout>

Remarque: Solution qui a fonctionné pour moi déjà expliquée dans le dernier commentaire de votre question

Meilleure explication: https://github.com/laenger/BottomSheetCoordinatorLayout

1
Ravindra Shekhawat

Essayez de ne pas utiliser NestedScrollView avec LinearLayout, cela a également causé des problèmes dans mon application. Utilisez simplement LinearLayout à la place, cela me convient.

Essayez ce qui suit:

<CoordinatorLayout
app:layout_behavior=“@string/bottom_sheet_behavior”>

<AppBarLayout>
    <CollapsingToolbarLayout>
       <ImageView />
    </CollapsingToolbarLayout>
</AppBarLayout>

<LinearLayout>
     <!--don't forget to addd this line-->
     app:layout_behavior="@string/appbar_scrolling_view_behavior">

        < Content ... />
</LinearLayout>
0
rahul

j'ai suivi le projet de test github initial de Laenger concernant ce problème, et je suis heureux de vous partager une solution pour certains de ses problèmes, car j'avais également besoin de ce comportement dans mon application.

c'est une solution à son problème: bar la barre d'outils s'effondre parfois trop tôt

pour éviter cela, vous devez créer votre AppBarLayout.Behavior personnalisé, car c'est lorsque vous faites défiler vers le haut tout en faisant glisser que le AppBarLayout.behavior obtient le mouvement de défilement. Nous devons détecter si c'est dans STATE_DRAGGING et simplement revenir pour éviter de masquer/réduire la barre d'outils prématurément.

public class CustomAppBarLayoutBehavior extends AppBarLayout.Behavior {

    private CoordinatorLayoutBottomSheetBehavior behavior;

    public CustomAppBarLayoutBehavior() {
    }

    public CustomAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        behavior = CoordinatorLayoutBottomSheetBehavior.from(parent);
        return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
        if(behavior.getState() == CoordinatorLayoutBottomSheetBehavior.STATE_DRAGGING){
            return;
        }else {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        }
    }

    @Override
    public void setDragCallback(@Nullable DragCallback callback) {
        super.setDragCallback(callback);
    }
}

cela peut être un bon début pour résoudre les autres problèmes:

Bar la barre d'outils ne peut pas être réduite par des traînées

Layout La disposition du coordinateur principal consomme du défilement

je ne suis pas vraiment une bonne personne en UI/animation, mais le travail acharné rapporte parfois la compréhension du code, en trouvant la bonne fonction de rappel/remplacement à implémenter.

définissez ce comportement sur appbarlayout

<Android.support.design.widget.AppBarLayout
    Android:id="@+id/bottom_sheet_appbar"
    style="@style/BottomSheetAppBarStyle"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    app:layout_behavior="your.package.CustomAppBarLayoutBehavior">
0
user3115201

Si le premier enfant est nestedscroll, cela entraînera d'autres problèmes. Cette solution est corrigée mon problème j'espère aussi résoudre le vôtre.

<CoordinatorLayout
    app:layout_behavior=“@string/bottom_sheet_behavior”>

   <AppBarLayout>
        <CollapsingToolbarLayout>
           <ImageView />
        </CollapsingToolbarLayout>
    </AppBarLayout>
</LinearLayout>
    <NestedScrollView>
        <LinearLayout>
            < Content ... />
        </LinearLayout>
    </NestedScrollView>
</LinearLayout>
</CoordinatorLayout>
0
Eren Utku