sheet example bottomsheetdialogfragment bottom android android-fragments android-support-library android-support-design

android - example - Establecer el estado de BottomSheetDialogFragment en expandido



bottom sheet android (9)

¿Cómo se configura el estado de un fragmento que extiende BottomSheetDialogFragment para expandirse usando BottomSheetBehavior#setState(STATE_EXPANDED) usando la Biblioteca de diseño de soporte de Android (v23.2.1)?

https://code.google.com/p/android/issues/detail?id=202396 dice:

Las hojas inferiores se establecen en STATE_COLLAPSED al principio. Llame a BottomSheetBehavior # setState (STATE_EXPANDED) si desea expandirlo. Tenga en cuenta que no puede llamar al método antes de ver los diseños.

La práctica sugerida requiere que primero se infle una vista, pero no estoy seguro de cómo estableceré BottomSheetBehaviour en un fragmento ( BottomSheetDialogFragment ).

View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet); BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);


"Tenga en cuenta que no puede llamar al método antes de ver los diseños".

El texto anterior es la pista.

Los cuadros de diálogo tienen un oyente que se activa una vez que se muestra el cuadro de diálogo. El cuadro de diálogo no se puede mostrar si no se presenta.

Entonces, en el onCreateDialog() de su hoja inferior modal ( BottomSheetFragment ), justo antes de devolver el cuadro de diálogo (o en cualquier lugar, una vez que tenga una referencia al cuadro de diálogo), llame al:

// This listener''s onShow is fired when the dialog is shown dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { // In a previous life I used this method to get handles to the positive and negative buttons // of a dialog in order to change their Typeface. Good ol'' days. BottomSheetDialog d = (BottomSheetDialog) dialog; // This is gotten directly from the source of BottomSheetDialog // in the wrapInBottomSheet() method FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet); // Right here! BottomSheetBehavior.from(bottomSheet) .setState(BottomSheetBehavior.STATE_EXPANDED); } });

En mi caso, mi BottomSheet personalizado resultó ser:

@SuppressWarnings("ConstantConditions") public class ShareBottomSheetFragment extends AppCompatDialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { BottomSheetDialog dialog = new BottomSheetDialog(getActivity(), R.style.Haute_Dialog_ShareImage); dialog.setContentView(R.layout.dialog_share_image); dialog.findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dismiss(); } }); dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { BottomSheetDialog d = (BottomSheetDialog) dialog; FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet); BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); } }); SwitchCompat switchview = (SwitchCompat) dialog.findViewById(R.id.switchview); switchview.setTypeface(FontCache.get(dialog.getContext(), lookup(muli, NORMAL))); return dialog; } }

Déjeme saber si esto ayuda.

ACTUALIZAR

Tenga en cuenta que también puede anular BottomSheetDialogFragment como:

public class SimpleInitiallyExpandedBottomSheetFragment extends BottomSheetDialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState); dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { BottomSheetDialog d = (BottomSheetDialog) dialog; FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet); BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); } }); // Do something with your dialog like setContentView() or whatever return dialog; } }

Pero realmente no veo por qué alguien querría hacer eso, ya que el BottomSheetFragment base no hace nada más que devolver un BottomSheetDialog .

ACTUALIZACIÓN PARA ANDROIDX

Al usar AndroidX, el recurso que se encontraba anteriormente en android.support.design.R.id.design_bottom_sheet ahora se puede encontrar en com.google.android.material.R.id.design_bottom_sheet .


Aplicar el estado BottomsheetDialogFragment en OnResume resolverá este problema

@Override public void onResume() { super.onResume(); if(mBehavior!=null) mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); }

onShow (diálogo DialogInterface) y postDelayed pueden causar fallas en la animación


Creo que los de arriba son mejores. Lamentablemente no encontré esa solución antes de haber resuelto. Pero escribe mi solución. bastante similar a todos

================================================== ================================

Me enfrento al mismo problema. Esto es lo que resolví. El comportamiento está oculto en BottomSheetDialog, que está disponible para obtener el comportamiento. Si desea no cambiar su diseño principal para que sea CooridateLayout, puede intentarlo.

PASO 1: personalice el BottomSheetDialogFragment

open class CBottomSheetDialogFragment : BottomSheetDialogFragment() { //wanna get the bottomSheetDialog protected lateinit var dialog : BottomSheetDialog override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog return dialog } //set the behavior here fun setFullScreen(){ dialog.behavior.state = STATE_EXPANDED } }

PASO 2: haga que su fragmento extienda este fragmento personalizado

class YourBottomSheetFragment : CBottomSheetDialogFragment(){ //make sure invoke this method after view is built //such as after OnActivityCreated(savedInstanceState: Bundle?) override fun onStart() { super.onStart() setFullScreen()//initiated at onActivityCreated(), onStart() } }


Escribí una subclase de BottomSheetDialogFragment para manejar esto:

public class NonCollapsableBottomSheetDialogFragment extends BottomSheetDialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState); bottomSheetDialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { FrameLayout bottomSheet = bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet); BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); behavior.setSkipCollapsed(true); behavior.setState(BottomSheetBehavior.STATE_EXPANDED); } }); return bottomSheetDialog; }

}

Por lo tanto, amplíe esta clase en lugar de BottomSheetDialogFragment para crear su propia hoja inferior.

Cambie com.google.android.material.R.id.design_bottom_sheet a android.support.design.R.id.design_bottom_sheet si su proyecto utiliza antiguas bibliotecas de soporte de Android.


La forma más fácil que implementé es la siguiente: Aquí encontramos android.support.design.R.id.design_bottom_sheet y configuramos el estado de la hoja inferior como EXPANDIDO .

Sin esto, mi hoja inferior siempre estaba atascada en el estado COLAPSED si la altura de la vista es más de 0.5 de la altura de la pantalla y tengo que desplazarme manualmente para ver la hoja inferior completa.

class BottomSheetDialogExpanded(context: Context) : BottomSheetDialog(context) { private lateinit var mBehavior: BottomSheetBehavior<FrameLayout> override fun setContentView(view: View) { super.setContentView(view) val bottomSheet = window.decorView.findViewById<View>(android.support.design.R.id.design_bottom_sheet) as FrameLayout mBehavior = BottomSheetBehavior.from(bottomSheet) mBehavior.state = BottomSheetBehavior.STATE_EXPANDED } override fun onStart() { super.onStart() mBehavior.state = BottomSheetBehavior.STATE_EXPANDED } }


La respuesta de efeturi es excelente, sin embargo, si desea usar onCreateView () para crear su BottomSheet, en lugar de ir con onCreateDialog () , aquí está el código que deberá agregar bajo su método onCreateView () :

@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { getDialog().setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { BottomSheetDialog d = (BottomSheetDialog) dialog; View bottomSheetInternal = d.findViewById(android.support.design.R.id.design_bottom_sheet); BottomSheetBehavior.from(bottomSheetInternal).setState(BottomSheetBehavior.STATE_EXPANDED); } }); return inflater.inflate(R.layout.your_bottomsheet_content_layout, container, false); }


Similar a la respuesta de uregentx , en kotlin , puede declarar su clase de fragmento que se extiende desde BottomSheetDialogFragment , y cuando se crea la vista, puede establecer el estado predeterminado del oyente de diálogo después de que se muestre el diálogo.

STATE_COLLAPSED: la hoja inferior es visible pero solo muestra su altura de vista.

STATE_EXPANDED: la hoja inferior es visible y su altura máxima.

STATE_HALF_EXPANDED: la hoja inferior es visible pero solo muestra su altura media.

class FragmentCreateGroup : BottomSheetDialogFragment() { ... override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? { // Set dialog initial state when shown dialog?.setOnShowListener { val bottomSheetDialog = it as BottomSheetDialog val sheetInternal: View = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet)!! BottomSheetBehavior.from(sheetInternal).state = BottomSheetBehavior.STATE_COLLAPSED } val view = inflater.inflate(R.layout.fragment_create_group, container, false) ... return view } }

Recuerde usar la implementación del diseño de materiales en gradle.

implementation "com.google.android.material:material:$version"

Consulte también las hojas de referencia de diseño de materiales.


Todos los resultados con el uso de onShow () provocan un error de renderizado aleatorio cuando se muestra el teclado virtual. Vea la captura de pantalla a continuación: el cuadro de diálogo BottomSheet no se encuentra en la parte inferior de la pantalla, sino que se coloca como se muestra el teclado. Este problema no se produce siempre, sino con bastante frecuencia.

ACTUALIZAR

Mi solución con reflejo de miembro privado es innecesaria. Usar postDelayed (con aproximadamente 100 ms) para crear y mostrar el diálogo después de ocultar el teclado virtual es una mejor solución. Entonces las soluciones anteriores con onShow () están bien.

Utils.hideSoftKeyboard(this); mView.postDelayed(new Runnable() { @Override public void run() { MyBottomSheetDialog dialog = new MyBottomSheetDialog(); dialog.setListener(MyActivity.this); dialog.show(getSupportFragmentManager(), TAG_BOTTOM_SHEET_DLG); } }, 100);

Así que implemento otra solución, pero requiere el uso de la reflexión, porque BottomSheetDialog tiene todos los miembros como privados. Pero resuelve el error de renderizado. La clase BottomSheetDialogFragment es solo AppCompatDialogFragment con el método onCreateDialog que crea BottomSheetDialog. Creo un hijo propio de AppCompatDialogFragment que crea mi clase extiende BottomSheetDialog y resuelve el acceso al miembro de comportamiento privado y lo establece en el método onStart al estado STATE_EXPANDED.

public class ExpandedBottomSheetDialog extends BottomSheetDialog { protected BottomSheetBehavior<FrameLayout> mBehavior; public ExpandedBottomSheetDialog(@NonNull Context context, @StyleRes int theme) { super(context, theme); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); try { Field privateField = BottomSheetDialog.class.getDeclaredField("mBehavior"); privateField.setAccessible(true); mBehavior = (BottomSheetBehavior<FrameLayout>) privateField.get(this); } catch (NoSuchFieldException e) { // do nothing } catch (IllegalAccessException e) { // do nothing } } @Override protected void onStart() { super.onStart(); if (mBehavior != null) { mBehavior.setSkipCollapsed(true); mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); } } } public class AddAttachmentBottomSheetDialog extends AppCompatDialogFragment { .... @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new ExpandedBottomSheetDialog(getContext(), getTheme()); } .... }


dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { BottomSheetDialog d = (BottomSheetDialog) dialog; FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet); BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); } });

Conocí a NullPointException en BottomSheetBehavior.from(bottomSheet) porque d.findViewById(android.support.design.R.id.design_bottom_sheet) devuelve nulo.

Es extraño. Agregué esta línea de código a Watches en Android Monitor en modo DEBUG y encontré que devuelve Framelayout normalmente.

Aquí está el código de wrapInBottomSheet en BottomSheetDialog:

private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) { final CoordinatorLayout coordinator = (CoordinatorLayout) View.inflate(getContext(), R.layout.design_bottom_sheet_dialog, null); if (layoutResId != 0 && view == null) { view = getLayoutInflater().inflate(layoutResId, coordinator, false); } FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet); BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(mBottomSheetCallback); if (params == null) { bottomSheet.addView(view); } else { bottomSheet.addView(view, params); } // We treat the CoordinatorLayout as outside the dialog though it is technically inside if (shouldWindowCloseOnTouchOutside()) { coordinator.findViewById(R.id.touch_outside).setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { if (isShowing()) { cancel(); } } }); } return coordinator; }

Ocasionalmente, descubrí que R.id.design_bottom_sheet no es igual a android.support.design.R.id.design_bottom_sheet . Tienen un valor diferente en diferentes R.java.

Así que cambio android.support.design.R.id.design_bottom_sheet a R.id.design_bottom_sheet .

dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { BottomSheetDialog d = (BottomSheetDialog) dialog; FrameLayout bottomSheet = (FrameLayout) d.findViewById(R.id.design_bottom_sheet); // use R.java of current project BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); } });

No más NullPointException ahora.