Uso de BottomSheetBehavior con un CoordinatorLayout interno

La biblioteca de soporte de diseño v. 23.2 introdujo BottomSheetBehavior , que permite que los niños de un coordinador actúen como hojas inferiores (vistas arrastrables desde la parte inferior de la pantalla).

Lo que me gustaría hacer es tener, como una vista inferior de la hoja , la siguiente vista (el coordinador típico + material colapsado):

 <CoordinatorLayout app:layout_behavior=“@string/bottom_sheet_behavior”> <AppBarLayout> <CollapsingToolbarLayout> <ImageView /> </CollapsingToolbarLayout> </AppBarLayout> <NestedScrollView> <LinearLayout> < Content ... /> </LinearLayout> </NestedScrollView> </CoordinatorLayout> 

Desafortunadamente, las vistas de la parte inferior de la hoja deben implementar el desplazamiento anidado o no obtendrán eventos de desplazamiento. Si intenta con una actividad principal y luego carga esta vista como una hoja inferior, verá que los eventos de desplazamiento sólo actúan en la "hoja" de papel, con algún comportamiento extraño, como puede ver si sigue leyendo.

Estoy bastante seguro de que esto puede ser manejado por subclase CoordinatorLayout , o incluso mejor por subclase BottomSheetBehavior . ¿Tiene alguna pista?

Algunos pensamientos

  • requestDisallowInterceptTouchEvent() debe utilizar, para robar eventos del padre en algunas condiciones:

    • Cuando el desplazamiento AppBarLayout es> 0
    • Cuando el desplazamiento de AppBarLayout es == 0, pero estamos desplazando hacia arriba (piense en ello por un segundo y verá)
  • La primera condición se puede obtener estableciendo un OnOffsetChanged en la barra de aplicación interna;

  • El segundo requiere un manejo de eventos, por ejemplo:

     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; } 

Cuestiones

Huelga decir que no puedo hacer que esto funcione ahora mismo. No soy capaz de captar los acontecimientos cuando se cumplen las condiciones, y no capturarlos en otros casos. En la imagen de abajo se puede ver lo que sucede con un CoordinatorLayout estándar:

  • La hoja se descarta si se desplaza hacia abajo en la barra de aplicaciones, pero no si se desplaza hacia abajo en el contenido anidado. Parece que los eventos de desplazamiento anidados no se propagan al comportamiento del Coordinador;

  • También existe un problema con la appbar interna: el contenido de desplazamiento anidado no sigue la barra de aplicaciones cuando se está contrayendo.

Introduzca aquí la descripción de la imagen

He configurado un proyecto de ejemplo en github que muestra estos problemas.

Sólo para ser claro, el comportamiento deseado es:

  • Comportamiento correcto de appbars / scroll views dentro de la hoja;

  • Cuando la hoja se expande, puede colapsar hacia abajo, pero sólo si la appbar interna está completamente expandida . Ahora mismo se derrumba sin tener en cuenta el estado de la appbar, y sólo si arrastra la appbar;

  • Cuando la hoja se contrae, los gestos de desplazamiento hacia arriba lo expandirán (sin efecto en la barra de herramientas interna).

Un ejemplo de la aplicación de contactos (que probablemente no utiliza BottomSheetBehavior, pero esto es lo que quiero):

Introduzca aquí la descripción de la imagen

Acabo de seguir la forma en que le hizo la pregunta anterior y llegar a la solución que podría necesitar más explicación. Por favor, siga su código de ejemplo e integrar la parte extra en su xml para que se comporten como BottomSheeet comportamiento

 <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> 

Nota: Solución que funcionó para mí ya explicada en el último comentario de tu pregunta

Mejor explicación: https://github.com/laenger/BottomSheetCoordinatorLayout

Por fin he liberado mi implementación. Encuentra en Github o directamente desde jcenter:

 compile 'com.otaliastudios:bottomsheetcoordinatorlayout:1.0.0' 

Todo lo que tienes que hacer es utilizar BottomSheetCoordinatorLayout como la vista raíz de tu hoja inferior. Inflará automáticamente un comportamiento de trabajo por sí mismo, así que no te preocupes por ello.

He estado usando esto durante mucho tiempo y no debe tener problemas de desplazamiento, apoya arrastrando en la ABL, etc

Si el primer niño es nestedscroll esto ocurrirá algunos otros problemas. Esta solución se soluciona mi problema espero también arreglar el suyo.

 <CoordinatorLayout app:layout_behavior=“@string/bottom_sheet_behavior”> <AppBarLayout> <CollapsingToolbarLayout> <ImageView /> </CollapsingToolbarLayout> </AppBarLayout> </LinearLayout> <NestedScrollView> <LinearLayout> < Content ... /> </LinearLayout> </NestedScrollView> </LinearLayout> </CoordinatorLayout> 

Trate de no utilizar NestedScrollView con LinearLayout , sino que ha estado causando problemas en mi aplicación también. Sólo utilice sólo LinearLayout en LinearLayout lugar, funciona bien para mí.

Pruebe lo siguiente:

 <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> 

He seguido el proyecto de prueba github inicial de laenger sobre este tema, y ​​me alegro de compartirte una solución para algunos de sus problemas, ya que necesitaba este comportamiento en mi aplicación también.

Esta es una solución a su problema: ❌ barra de herramientas a veces colapsa demasiado pronto

Para evitar esto, debe crear su AppBarLayout.Behavior personalizado, ya que es cuando se desplaza hacia arriba mientras arrastra que AppBarLayout.behavior obtiene el movimiento de desplazamiento. Necesitamos detectar si está en STATE_DRAGGING y simplemente regresar para evitar ocultar / contraer la barra de herramientas prematuramente.

 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); } } 

Esto puede ser un buen comienzo en cómo resolver los otros problemas:

❌ la barra de herramientas no se puede colapsar a través de arrastra

❌ el diseño del coordinador principal consume algunos desplazamientos

En realidad no soy una buena persona de UI / animación, pero hardwork vale la pena entender el código a veces, encontrar la función de devolución de llamada derecha / reemplazar a implementar.

Establezca esto como comportamiento para 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"> 

El diseño de la pantalla completa del diseño de appbar es el siguiente:

 <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="@dimen/detail_backdrop_height" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:fitsSystemWindows="true"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:expandedTitleMarginStart="48dp" app:expandedTitleMarginEnd="64dp"> <ImageView android:id="@+id/backdrop" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:fitsSystemWindows="true" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingTop="24dp"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/card_margin"> <LinearLayout style="@style/Widget.CardContent" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Info" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/cheese_ipsum" /> </LinearLayout> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/card_margin" android:layout_marginLeft="@dimen/card_margin" android:layout_marginRight="@dimen/card_margin"> <LinearLayout style="@style/Widget.CardContent" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Friends" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/cheese_ipsum" /> </LinearLayout> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/card_margin" android:layout_marginLeft="@dimen/card_margin" android:layout_marginRight="@dimen/card_margin"> <LinearLayout style="@style/Widget.CardContent" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Related" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/cheese_ipsum" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:layout_height="wrap_content" android:layout_width="wrap_content" app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end" android:src="@drawable/ic_discuss" android:layout_margin="@dimen/fab_margin" android:clickable="true"/> 

Y después de eso debe implementar AppBarLayout.OnOffsetChangedListener en su clase y establecer el desplazamiento de la pantalla.

  • Preferences Support Library - SwitchPreference no funciona
  • Soporte de transición de fragmentos 25.1.0 con Recyclerview
  • Biblioteca FloatingActionButton de terceros en CoordinatorLayout
  • La biblioteca de soporte de Android v4 y la API de Google Maps rompen la compilación
  • Agregue soporte JS y CSS al proyecto de Android Studio
  • Android SearchView no funciona
  • CoordinatorLayout reemplazando Fragments
  • Problema de superposición de sugerencias de TextInputLayout
  • ¿Cómo manejar los problemas de la nueva hoja inferior de la biblioteca de soporte / diseño?
  • Cómo utilizar o solucionar la búsqueda searchManager.getSearchableInfo () en Android API 7?
  • Snackbar.setCallback () no se puede resolver en Android AppCompat
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.