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:
Se coince:
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.
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);
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.
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
@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:
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();
Remplacez ou enveloppez la FrameLayout
à l'intérieur du Android.support.design.widget.CoordinatorLayout
par unAndroid.support.v4.widget.NestedScrollView
et 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>
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