web-dev-qa-db-fra.com

Comment réinitialiser la position de la barre d’outils contrôlée par CoordinatorLayout?

L'application sur laquelle je travaille est constituée d'un tiroir de navigation implémenté dans une activité. La structure de l'activité est la suivante:

<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

<Android.support.v4.widget.DrawerLayout
    Android:id="@+id/drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <Android.support.design.widget.CoordinatorLayout
        Android:id="@+id/coordinator"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent">

        <FrameLayout
            Android:id="@+id/container"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <include
            Android:id="@+id/appbar"
            layout="@layout/appbar" />

    </Android.support.design.widget.CoordinatorLayout>

    <Android.support.design.widget.NavigationView
        Android:id="@+id/navigation_drawer"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_gravity="start"
        app:headerLayout="@layout/header_drawer"
        app:menu="@menu/menu_nav">
    </Android.support.design.widget.NavigationView>

</Android.support.v4.widget.DrawerLayout>

</FrameLayout>

C'est un motif très courant, la seule chose qui change fréquemment est le fragment à l'intérieur de la disposition du conteneur.

Si l'un des fragments contient un élément de défilement, il se fera une joie de traduire les positions, y compris la barre d'outils/AppBarLayout.

Le vrai problème est que, lorsque le fragment est remplacé, la position de la barre d’outils reste la même, c’est-à-dire que si la barre d’outils est masquée, elle le restera. Ce qui n’est pas prévu. 

Le résultat est ceci:

Ce:

After scroll

Se coince:

Then change

Comment peut-on réinitialiser la position de la barre d'outils pour ce cas?

EDIT: Un bogue est probable, l'écouteur de changement de décalage AppBarLayout est appelé uniquement lors de la relance de l'application (appuyez sur le bouton Précédent pour ouvrir l'application) et cesse de se faire appeler après une session intense.

47
razzledazzle

Pour réinitialiser l'état de défilement, récupérez simplement l'objet AppBarLayout.Behavior

CoordinatorLayout coordinator = (CoordinatorLayout) findViewById(R.id.coordinator);
AppBarLayout appbar = (AppBarLayout) findViewById(R.id.appbar);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();       

et appelez la méthode onNestedPreScroll manuellement:

int[] consumed = new int[2];
behavior.onNestedPreScroll(coordinator, appbar, null, 0, -1000, consumed);

Si vous souhaitez réinitialiser en douceur avec une animation, vous pouvez essayer d'appeler onNestedFling à la place:

behavior.onNestedFling(coordinator, appbar, null, 0, -1000, true);
46
MattSkala

Commencez par obtenir une référence AppBarLayout dans MainActivity, puis dans l'état de pause du fragment en cours de remplacement, utilisez la méthode ci-dessous pour développer la barre d'outils:

MainActivity.appbar.setExpanded(true,true);

Et ou pour fermer la barre d’outils:

MainActivity.appbar.setExpanded(false,true);

Le deuxième paramètre est utilisé pour faire défiler la barre d’outils en douceur.

31
Shayan Shafiee

Mettez à jour votre librairie de support en v23 pour pouvoir utiliser:

appBarLayout.setExpanded(true/false);

public void setExpanded (boolean expand )

Définit si cette AppBarLayout est développée ou non, en animant si elle a déjà été aménagée.

Comme pour le défilement de AppBarLayout, cette méthode repose sur le fait que cette présentation est un enfant direct d'un CoordinatorLayout.

expand true si la mise en page doit être entièrement développée, false si elle doit être entièrement réduite

12
Context

@razzledazzle AppBarLayout stocke les écouteursOffsetChangedListeners en tant que WeakReferences, ce qui signifie qu'ils sont récupérés à la poubelle si nécessaire, par exemple lorsque vous faites une aventure intense. Voir la solution ici:

https://code.google.com/p/Android/issues/detail?id=176328

3
freebiefalk

J'utilise ces codes avant les changements de fragments.

scrollingElement.startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
scrollingElement.dispatchNestedPreScroll(0, -Integer.MAX_VALUE, null, null);
scrollingElement.stopNestedScroll();
2
weumj

Remplacez ou enveloppez la FrameLayout à l'intérieur du Android.support.design.widget.CoordinatorLayout par unAndroid.support.v4.widget.NestedScrollViewet cela fera le travail automatiquement sans qu'il soit nécessaire de recourir à d'autres hacks ....

<Android.support.design.widget.CoordinatorLayout
    Android:id="@+id/coordinator"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <Android.support.v4.widget.NestedScrollView
        Android:id="@+id/container"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <include
        Android:id="@+id/appbar"
        layout="@layout/appbar" />

</Android.support.design.widget.CoordinatorLayout>
1

Comme document dit 

AppBarLayout prend en charge
void setExpanded (booléen développé, booléen animé);
Définit si cet AppBarLayout est développé ou non.

  • expand boolean: true si la mise en page doit être entièrement développée, false si elle doit être entièrement réduite 
  • animate boolean: Faut-il animer le nouvel état? 

Donc au début vous avez besoin 

AppBarLayout appBarLayout = (AppBarLayout)findViewById(R.id.appBarLayout);

puis à expand layout 

appBarLayout.setExpanded(true, true); // with animation
appBarLayout.setExpanded(true, false); // without animation  

et à collapse layout 

appBarLayout.setExpanded(false, true); // with animation
appBarLayout.setExpanded(false, false); // without animation 
0
hassan moradnezhad