Android: cómo deshabilitar el estado STATE_HALF_EXPANDED de una hoja inferior

14

Tengo una hoja inferior que debe ir entre 2 estados, STATE_COLLAPSEDy STATE_EXPANDED cuando se colapsa, la altura debería ser 200dpy cuando se expande, será a pantalla completa.

Así que estoy configurando el BottomSheetBehaviorcon

isFitToContents = false
peekHeight = 200dp

y me veo obligado a establecer un valor de lo halfExpandedRatiocontrario cuando en STATE_HALF_EXPANDEDla hoja inferior ocupará la mitad de la pantalla.

Estoy trabajando w / com.google.android.material:material:1.1.0-rc01

¿Hay alguna manera de deshabilitar el STATE_HALF_EXPANDEDestado?

O debería establecer skipCollapsed=true, averiguar en términos de proporción lo que significa 200dp y trabajar con STATE_HALF_EXPANDEDy en STATE_EXPANDEDlugar de STATE_COLLAPSEDySTATE_EXPANDED

Noa Drach
fuente
proporcione más detalles como, por ejemplo, cómo se ve la hoja inferior.
UD ..
@ UD ... No creo que el contenido de la hoja inferior sea relevante en este caso. Esta es una pregunta más general, ¿es posible deshabilitar uno de los estados de la hoja inferior
Noa Drach
1
Para mi caso de uso, parece que la configuración halfExpandedRatio=0.25fy peekHeight = 200dpluego el tratamiento STATE_COLLAPSEDy STATE_HALF_EXPANDEDcomo si fueran el mismo estado resuelven el problema. Mantener la pregunta abierta en caso de que haya otras ideas.
Noa Drach
puedes seguir este enlace, ayudará a androidhive.info/2017/12/android-working-with-bottom-sheet
UD ..
¡Asegúrese de aceptar una de estas respuestas si cumple con los objetivos establecidos en su pregunta!
CommonsWare

Respuestas:

3

El valor de la relación media expandida debe establecerse en un valor entre 0 y 1 exclusivo , por lo tanto, establezca este valor en un número muy bajo que seguramente sea menor que la altura de su vista, diga "0.0001f". Con este valor, ni siquiera debería ver el STATE_HALF_EXPANDEDestado. Los estados fluctuarán entre STATE_EXPANDEDy STATE_COLLAPSED.


Solución alternativa

La solución anterior funciona y deshabilita efectivamente el STATE_HALF_EXPANDEDestado, pero es hack (IMO) y puede romperse en el futuro. Por ejemplo, ¿qué sucede si se aplica un valor razonable para la relación medio expandida que está en algún lugar entre la altura de vista y la altura completa? Eso sería un problema.

Los requisitos según lo establecido por el OP es que la hoja inferior debe hacer la transición entre la altura de vista y la altura completa. No hay ningún problema con la altura de vista, pero el OP especifica isFitToContents = falseque se llegue a la altura completa. (Supongo que su hoja inferior puede ser más corta que el espacio disponible).

Desafortunadamente, cuando isFitToContents == falsese introduce un comportamiento adicional de "media altura" que el OP quiere evitar y, por lo tanto, la pregunta.

Además del comportamiento de "media altura", se introduce otro comportamiento que es el "desplazamiento expandido". El desplazamiento expandido especifica qué tan lejos de la pantalla completa se detendrá la hoja inferior. Un valor de 100f, por ejemplo, dejará un 100pxborde en la parte superior de la hoja inferior cuando esté completamente expandido. El valor predeterminado para el desplazamiento expandido es cero.

No conozco ningún comportamiento que isFitToContents == falsepresente otros que no sean los mencionados anteriormente.

Entonces, dados estos requisitos, ¿podemos diseñar una hoja inferior que se mueva entre la altura de la vista y la altura completa mientras especificamos isFitToContents == true , evitando así el problema de "media altura"? No hay requisitos para un desplazamiento expandido distinto de cero, por lo que no tenemos que preocuparnos por eso.

Aquí hay una breve aplicación de demostración que demuestra que podemos cumplir estos requisitos con la estructura de hoja inferior derecha:

ingrese la descripción de la imagen aquí

MainActivity5.kt

class MainActivity5 : BaseActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.activity_main5)  

        val bottomSheet = findViewById<LinearLayout>(R.id.bottom_sheet)  
        val sheetBehavior: BottomSheetBehavior<LinearLayout> = BottomSheetBehavior.from(bottomSheet)  
        sheetBehavior.isFitToContents = true // the default  
  sheetBehavior.peekHeight = 200  

  // Log the states the bottom sheet passes through.  
  sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {  
            override fun onStateChanged(bottomSheet: View, newState: Int) {  
                Log.d("MainActivity", "<<<< $newState = ${translateSheetState(newState)}")  
            }  

            override fun onSlide(bottomSheet: View, slideOffset: Float) {}  
        })  
    }  
}

BaseActivity.kt

open class BaseActivity : AppCompatActivity() {  

    protected fun translateSheetState(state: Int): String {  
        return when (state) {  
            BottomSheetBehavior.STATE_COLLAPSED -> "STATE_COLLAPSED"  
  BottomSheetBehavior.STATE_DRAGGING -> "STATE_DRAGGING"  
  BottomSheetBehavior.STATE_EXPANDED -> "STATE_EXPANDED"  
  BottomSheetBehavior.STATE_HALF_EXPANDED -> "STATE_HALF_EXPANDED"  
  BottomSheetBehavior.STATE_HIDDEN -> "STATE_HIDDEN"  
  BottomSheetBehavior.STATE_SETTLING -> "STATE_SETTLING"  
  else -> "Unknown state: $state"  
  }  
    }  
}

activity_main5.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_orange_light"
        android:orientation="vertical"
        android:scrollbars="none"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="@string/short_text"
            android:textSize="16sp" />

    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Si tenemos una hoja inferior larga, la siguiente estructura funciona para desplazarla:

activity_main6.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_orange_light"
        android:orientation="vertical"
        android:scrollbars="none"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="16dp"
                android:text="@string/long_text"
                android:textSize="16sp" />
        </androidx.core.widget.NestedScrollView>
    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Cheticamp
fuente
con respecto a su respuesta inicial: vi que incluso si establezco una relación medio expandida, todavía se puede ver una pista muy delgada de la hoja inferior. Y de todos modos, este no es el comportamiento que estoy buscando. como mencionó en "Solución alternativa" - "la hoja inferior debe hacer la transición entre la altura máxima y la altura total"
Noa Drach
su "solución alternativa" parece estar funcionando y es la solución que necesitaba, mis pruebas iniciales mostraron que necesito usar isFitToContents = false, pero las pruebas ahora isFitToContents = truefuncionan bien
Noa Drach
@NoaDrach Si la hoja inferior es ocultable, se mostrará al menos 1 px en la parte inferior debido a cómo se calcula el desplazamiento de la hoja inferior. No estaba pensando que la hoja estaría oculta, pero, al mostrar 1px, la hoja podría verse obligada a ocultarse sheetBehavior.state = BottomSheetBehavior.STATE_HIDDENcuando se alcanza el estado medio expandido, pero eso se está volviendo un poco complicado. La solución alternativa es mejor.
Cheticamp
2

ingrese la descripción de la imagen aquí

Si quieres probar arriba como en la imagen, puedes seguir el código a continuación, ¡puede que te ayude!

public class CollectionsBottomSheet extends BottomSheetDialogFragment {
    private BottomSheetBehavior mBehavior;


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
        View view = View.inflate(getContext(), R.layout.collections_layout, null);
        LinearLayout linearLayout = view.findViewById(R.id.root);
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) linearLayout.getLayoutParams();
        params.height = getScreenHeight();
        linearLayout.setLayoutParams(params);
        dialog.setContentView(view);
        mBehavior = BottomSheetBehavior.from((View) view.getParent());
        return dialog;

    }

    @Override
    public void onStart() {
        super.onStart();
        mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }

    public static int getScreenHeight() {
        return Resources.getSystem().getDisplayMetrics().heightPixels;
    }
}



xml 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:fitsSystemWindows="true">


    <LinearLayout
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/filter_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:drawableStart="@drawable/ic_cancel"
                android:drawableLeft="@drawable/ic_cancel"
                android:drawablePadding="30dp"
                android:gravity="center_vertical"
                android:padding="12dp"
                android:text="Filters"
                android:textColor="@color/black"
                android:textSize="18sp" />

            <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:layout_marginEnd="10dp"
                android:layout_marginRight="10dp"
                android:padding="5dp"
                android:text="Reset ALL"
                android:textColor="#6f6f6f"
                android:textSize="12sp" />

        </LinearLayout>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#d8dbdb" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_star"
            android:drawableLeft="@drawable/ic_star"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="GUEST RATINGS"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_money"
            android:drawableLeft="@drawable/ic_money"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="PRICE RANGE"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_loan"
            android:drawableLeft="@drawable/ic_star"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="PAY AT HOTEL"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_folder"
            android:drawableLeft="@drawable/ic_folder"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="COLLECTIONS"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_perm_identity_black_24dp"
            android:drawableLeft="@drawable/ic_perm_identity_black_24dp"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="FACILITIES"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_apartment"
            android:drawableLeft="@drawable/ic_apartment"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="CATEGORIES"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_hotel_building"
            android:drawableLeft="@drawable/ic_hotel_building"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="ACCOMMODATION TYPE"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

    </LinearLayout>


</LinearLayout>
UD ..
fuente
muy buena respuesta ... me salvó el día
unownsp
1

intente configurar un addBottomSheetCallbacken su BottomSheetBehavior, y cuando detecte un STATE_HALF_EXPANDEDestado, llame setState(STATE_HIDDEN)para que cada vez que la hoja inferior intente alcanzar el estado intermedio, simplemente se cierre.

marmor
fuente
Buena idea, en mi caso establecería el estado en STATE_COLLAPSEDy no STATE_HIDDEN. Pero intenté implementarlo y la transición de STATE_HALF_EXPANDEDa se STATE_COLLAPSEDsiente torpe. La transición entre estados es animada, por lo que verá la hoja inferior deteniéndose STATE_HALF_EXPANDEDy luego se mueve aSTATE_COLLAPSED
Noa Drach
¿Podrías combinar esto con un HalfExpandedRatio de 0?
Ridcully
@Ridcully - 2 problemas aquí - 1. halfExpandedRatio debe estar por encima de 0 2. establecerlo en un valor muy bajo hará que se minimice casi por completo (estado medio expandido), antes de ser ajustado al estado colapsado. Pensé en combinar esta sugerencia con mi solución de trabajo de halfExpandedState=0.25f, b / c, entonces la transición entre estados no será tan obvia. Pero, no estoy seguro de que será un gran cambio en comparación con lo que ya tengo
Noa Drach
1

Tuve un caso de uso similar donde el diseño tenía que ser un tercio de la altura. Intenté lo siguiente y funcionó muy bien.

<androidx.coordinatorlayout.widget.CoordinatorLayout 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:id="@+id/bottom_sheet_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/grey"
    android:clickable="true">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/rounded_bottom_sheet_background"
        android:orientation="vertical"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Tuve que cambiarlos dinámicamente, así que configuré lo siguiente en la hoja inferior, pero también puedes hacerlo en xml:

bottomSheet.setPeekHeight(200);// 200px
bottomSheet.setHideable(false);

Para descartar, agregué animación a mi fragmento usando la siguiente función:

fragmentTransaction.setCustomAnimations(
                    R.anim.fade_in,
                    R.anim.fade_out,
                    R.anim.fade_in,
                    R.anim.fade_out)

Espero que esto ayude

Saurabh
fuente
0

Intenté diferentes formas, pero ninguna técnica funcionó a la perfección. Traté de interceptar eventos BottomSheetBehavior.BottomSheetCallback {}y llamédismiss() base a una lógica personalizada, pero causó un tirón.

Entonces, por fin, en mi BottomSheetDialogFragmentagreguébottomSheetBehavior.isDraggable = false y esto causó el arrastre de la hoja inferior al tacto Y, manejé el rechazo del diálogo por mi cuenta. en el diálogo de área vacía de todos modos se descarta.

Tenga en cuenta que, la hoja inferior todavía se expande con animación. ¡Eso es realmente genial!

anular diversión onCreateDialog (savedInstanceState: Bundle?): Dialog {val dialog = super.onCreateDialog (savedInstanceState)

    dialog.setOnShowListener {
        val bottomSheetDialog = it as BottomSheetDialog
        val bottomSheet =
            bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
                ?: return@setOnShowListener

        //Making background to transparent to avoid white background to given space margin.
        bottomSheet.setBackgroundColor(ContextCompat.getColor(context!!, R.color.transparent))

        val inflatedView = fragmentProfileDialogBinding.root
        val parent = inflatedView.parent as View

        val bottomSheetBehavior = BottomSheetBehavior.from(parent)
        bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
        bottomSheetBehavior.isDraggable = false
    }

    return dialog
}
Rahul Rastogi
fuente