Detener AppBarLayout desplazarse fuera de la pantalla cuando NestedScrollView está vacío
Tengo una característica bastante típica de la lista usando un CoordinatorLayout, AppBarLayout, SwipeRefreshLayout y RecyclerView –
Cuando el RecyclerView tiene suficiente contenido para desplazarse, la página parece estar bien. Cuando el RecyclerView está vacío o no tiene suficiente contenido para desplazarse, sin embargo, el comportamiento es que los niños de AppBarLayout con app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
continuarán app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
– lo que parece extraño.
- Barra de herramientas en AppBarLayout es desplazable aunque RecyclerView no tiene suficiente contenido para desplazarse
- Cómo hacer transparente el fondo AppBarLayout
- AppBarLayout fitsSystemWindows true attr hace que CircularIndicator sea invisible
- Cómo expandir AppBarLayout al desplazarse hacia abajo alcanza en la parte superior de la RecyclerView
- Ver saltos y parpadea al instante, aunque animateLayoutChanges = "true"
¿Hay una manera de detener el desplazamiento de los niños de AppBarLayout cuando el NestedScrollView está vacío?
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.CoordinatorLayout android:id="@+id/coordinatorLayout" android:background="@android:color/transparent" 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:background="@android:color/transparent" android:elevation="4dp"> <LinearLayout android:id="@+id/eventHeader" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:background="@color/green" android:orientation="horizontal" app:layout_scrollFlags="scroll|enterAlwaysCollapsed"> <View android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="1"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="scroll|enterAlwaysCollapsed" android:textColor="@color/white" android:textSize="15sp"/> <View android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="1"/> </LinearLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeToRefresh" android:layout_width="match_parent" android:layout_gravity="fill_vertical" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:dividerHeight="0dp" android:layout_gravity="fill_vertical" android:drawSelectorOnTop="true" android:listSelector="@drawable/selector_ripple_grey_transparent" android:scrollbars="vertical"/> </android.support.v4.widget.SwipeRefreshLayout> </android.support.design.widget.CoordinatorLayout> <TextView android:id="@+id/noData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="16dp" android:text="@string/no_data_available" android:textSize="17sp"/> </FrameLayout>
- Programe ocultar / mostrar el diseño de soporte de Android Android TabLayout dentro de AppBarLayout
- AppBarLayout con recyclerView en fragmento anidado
- Comportamiento extraño del CoordinatorLayout junto con ViewPager
- AppBarLayout no siempre vuelve a entrar en desplazamiento hacia abajo
- Despliegue anidado de ListView en la API <21
- Disposición de Android: Recyclerview horizontal dentro de una Recyclerview vertical dentro de un Viewpager con comportamientos de desplazamiento
- CoordinatorLayout con barra de herramientas y fragmento
- Cómo desplazarse hacia arriba / abajo de la barra inferior en el desplazamiento de RecyclerView
No estoy seguro de lo elegante que es una solución, pero, he sobrepasado el evento onStartNestedScroll()
para disparar sólo si el NestedScrollView es desplazable (en este caso, un RecyclerView)
En onCreate ():
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams(); layoutParams.setBehavior(new AppBarLayoutNoEmptyScrollBehavior(mAppBarLayout, mRecyclerView));
Comportamiento:
public class AppBarLayoutNoEmptyScrollBehavior extends AppBarLayout.Behavior { AppBarLayout mAppBarLayout; RecyclerView mRecyclerView; public AppBarLayoutNoEmptyScrollBehavior(AppBarLayout appBarLayout, RecyclerView recyclerView) { mAppBarLayout = appBarLayout; mRecyclerView = recyclerView; } public boolean isRecylerViewScrollable(RecyclerView recyclerView) { int recyclerViewHeight = recyclerView.getHeight(); // Height includes RecyclerView plus AppBarLayout at same level int appCompatHeight = mAppBarLayout != null ? mAppBarLayout.getHeight() : 0; recyclerViewHeight -= appCompatHeight; return recyclerView.computeVerticalScrollRange() > recyclerViewHeight; } @Override public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) { if (isRecylerViewScrollable(mRecyclerView)) { return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes); } return false; } }
EDITAR
Solución editada como RecyclerView da altura como altura visible de RecyclerView y altura de AppBarLayout (que es la altura de CoordinatorLayout).
Sin embargo, si su gesto de desplazamiento comienza en el área visible AppBarLayout, un desplazamiento todavía se llevará a cabo, incluso si agrega este comportamiento al AppBarLayout también. Esta respuesta por lo tanto no es una solución para el problema.
(Basado en: Referencia )
(1) Cree esta clase.
public class AppBarLayoutBehaviorForEmptyRecyclerView extends AppBarLayout.Behavior { private boolean canRecyclerViewBeScrolled = false; public AppBarLayoutBehaviorForEmptyRecyclerView() { } public AppBarLayoutBehaviorForEmptyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) { return canRecyclerViewBeScrolled && super.onInterceptTouchEvent(parent, child, ev); } @Override public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) { updateScrollable(target); return canRecyclerViewBeScrolled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes); } @Override public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) { return canRecyclerViewBeScrolled && super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); } private void updateScrollable(View targetChild) { if(targetChild instanceof RecyclerView) { RecyclerView.Adapter adapter = ((RecyclerView) targetChild).getAdapter(); canRecyclerViewBeScrolled = adapter != null && adapter.getItemCount() > 0; } else { canRecyclerViewBeScrolled = true; } } }
(2) Agregue a su elemento XML AppBarLayout
el siguiente atributo:
app:layout_behavior="com.xxxx.xxxxxx.AppBarLayoutBehaviorForEmptyRecyclerView"
Después de cargar los datos en su RecyclerView, si está vacía, simplemente despliegue la bandera de desplazamiento manualmente:
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mEventHeader.getLayoutParams(); toolbarLayoutParams.setScrollFlags(0); mEventHeader.setLayoutParams(toolbarLayoutParams);
Y si no está vacío, retroceda la bandera de desplazamiento:
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mEventHeader.getLayoutParams(); toolbarLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); mEventHeader.setLayoutParams(toolbarLayoutParams);
Graeme respuesta está bien, pero también se agregó en el constructor
public AppBarLayoutOnEmptyRecyclerViewScrollBehavior(@NonNull AppBarLayout appBarLayout, @NonNull RecyclerView recyclerView) { this.appBarLayout = checkNotNull(appBarLayout); this.recyclerView = checkNotNull(recyclerView); setDragCallback(new DragCallback() { @Override public boolean canDrag(@NonNull AppBarLayout appBarLayout) { return isRecylerViewScrollable(recyclerView); } }); }
Así que cuando RecyclerView
está vacío también deshabilito el arrastre de AppBarLayout
- Android: el proceso ha muerto
- ¿Por qué GoogleMap.animateCamera () se bloquea después de onGlobalLayout ()?