J'ai créé une application à l'aide de Android Design Library, avec une barre d'outils et TabLayout.
En réalité, 2 onglets sont présents, les deux avec 2 RecyclerView, qui réduisent automatiquement la barre d'outils lors du défilement.
Ma question est la suivante: puis-je désactiver la réduction de la barre d'outils lorsque RecyclerView comporte peu d'éléments et s'adapte parfaitement à l'écran (comme dans l'onglet 2)?
J'ai vu beaucoup d'exemples tels que CheeseSquare , créés par un employé de Google où le problème est toujours présent: même si le RecyclerView ne contient qu'un élément, la barre d'outils continue de se cacher lors du défilement.
Je pense que je peux simplement savoir si le premier élément de RecyclerView est visible à l'écran et si oui, désactiver la réduction de la barre d'outils. Le premier est facile à mettre en œuvre, qu'en est-il du dernier?
Ceci est ma mise en page:
<Android.support.design.widget.CoordinatorLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/coordinator_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.design.widget.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:fitsSystemWindows="true"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
Android:background="?attr/colorPrimary"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
<Android.support.design.widget.TabLayout
Android:id="@+id/tab_layout"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="@color/glucosio_pink"
app:tabSelectedTextColor="@Android:color/white"
app:tabIndicatorColor="@color/glucosio_accent"
app:tabTextColor="#80ffffff"/>
</Android.support.design.widget.AppBarLayout>
<Android.support.v4.view.ViewPager
Android:id="@+id/pager"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"/>
<Android.support.design.widget.FloatingActionButton
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:id="@+id/main_fab"
Android:layout_margin="16dp"
Android:onClick="onFabClicked"
app:backgroundTint="@color/glucosio_accent"
Android:src="@drawable/ic_add_black_24dp"
Android:layout_gravity="bottom|right"
/>
</Android.support.design.widget.CoordinatorLayout>
Solution finale (merci Michał Z.)
Méthodes pour activer/désactiver le défilement de la barre d’outils:
public void turnOffToolbarScrolling() {
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar_layout);
//turn off scrolling
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
toolbarLayoutParams.setScrollFlags(0);
mToolbar.setLayoutParams(toolbarLayoutParams);
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(null);
appBarLayout.setLayoutParams(appBarLayoutParams);
}
public void turnOnToolbarScrolling() {
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar_layout);
//turn on scrolling
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
toolbarLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
mToolbar.setLayoutParams(toolbarLayoutParams);
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(new AppBarLayout.Behavior());
appBarLayout.setLayoutParams(appBarLayoutParams);
}
Découvrez si le dernier élément de RecyclerView est visible dans mon fragment.
Si oui, désactiver le défilement:
public void updateToolbarBehaviour(){
if (mLayoutManager.findLastCompletelyVisibleItemPosition() == items.size()-1) {
((MainActivity) getActivity()).turnOffToolbarScrolling();
} else {
((MainActivity)getActivity()).turnOnToolbarScrolling();
}
}
RecyclerView
maintenant (depuis la version 23.2) supporte wrap_content
. Il suffit d'utiliser wrap_content
comme hauteur.
Vous pouvez vérifier si le dernier élément de RecyclerView
est visible. Si ce n'est pas le cas, désactivez le défilement par programmation à l'aide de cette méthode:
//turn off scrolling
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
toolbarLayoutParams.setScrollFlags(0);
mToolbar.setLayoutParams(toolbarLayoutParams);
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(null);
appBarLayout.setLayoutParams(appBarLayoutParams);
J'ai adopté une approche légèrement différente pour résoudre ce problème.
J'ai créé un AppBarBehavior personnalisé qui désactive son auto en fonction des cellules.
public class CustomAppBarBehavior extends AppBarLayout.Behavior {
private RecyclerView recyclerView;
private boolean enabled;
public CustomAppBarBehavior() {
}
public CustomAppBarBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
updatedEnabled();
return enabled && super.onInterceptTouchEvent(parent, child, ev);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
return enabled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
}
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
return enabled && super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
}
private void updatedEnabled() {
enabled = false;
if(recyclerView != null) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter != null) {
int count = adapter.getItemCount();
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager != null) {
int lastItem = 0;
if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
lastItem = Math.abs(linearLayoutManager.findLastCompletelyVisibleItemPosition());
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
int[] lastItems = staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(new int[staggeredGridLayoutManager.getSpanCount()]);
lastItem = Math.abs(lastItems[lastItems.length - 1]);
}
enabled = lastItem < count - 1;
}
}
}
}
public void setRecyclerView(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}
}
Puis définissez le comportement personnalisé sur la présentation de la barre d'applications
appBarBehavior = new CustomAppBarBehavior();
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(appBarBehavior);
appBarLayout.setLayoutParams(appBarLayoutParams);
Dernier changement de page du pager de vue mis à jour le RecyclerView sur le comportement
private ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
@Override
public void onPageSelected(final int position) {
appBarLayout.setExpanded(true, true);
appBarLayout.post(new Runnable() {
@Override
public void run() {
appBarBehavior.setRecyclerView(childFragments.get(position).getRecyclerView());
}
});
}
@Override
public void onPageScrollStateChanged(int state) { }
};
Cela devrait fonctionner avec des ensembles de données changeants.
Ajoutez ce code après avoir modifié les données de votre adaptateur:
recyclerView.afterMeasured {
val isTurnedOff = recyclerView.turnOffNestedScrollingIfEnoughItems()
if (isTurnedOff) appBarLayout.setExpanded(true)
}
Et voici les fonctions:
inline fun <T: View> T.afterMeasured(crossinline action: T.() -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
action()
}
})
}
fun RecyclerView.turnOffNestedScrollingIfEnoughItems(): Boolean {
val lm = (layoutManager as LinearLayoutManager)
val count = if (lm.itemCount <= 0) 0 else lm.itemCount - 1
val isFirstVisible = lm.findFirstCompletelyVisibleItemPosition() == 0
val isLastItemVisible = lm.findLastCompletelyVisibleItemPosition() == count
isNestedScrollingEnabled = !(isLastItemVisible && isFirstVisible)
return isNestedScrollingEnabled.not()
}