"Notez que vous ne pouvez pas appeler la méthode avant d'afficher les mises en page."
Le texte ci-dessus est l'indice.
Les boîtes de dialogue ont un écouteur qui est déclenché une fois la boîte de dialogue affichée . La boîte de dialogue ne peut pas être affichée si elle n'est pas mise en page.
Donc, dans le onCreateDialog()
de votre feuille de fond modale ( BottomSheetFragment
), juste avant de retourner la boîte de dialogue (ou n'importe où, une fois que vous avez une référence à la boîte de dialogue), appelez:
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);
}
});
Dans mon cas, ma coutume BottomSheet
s'est avérée être:
@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;
}
}
Faites-moi savoir si cela vous aide.
MISE À JOUR
Notez que vous pouvez également remplacer BottomSheetDialogFragment
comme:
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);
}
});
return dialog;
}
}
Mais je ne vois vraiment pas pourquoi quelqu'un voudrait faire cela car la base BottomSheetFragment
ne fait rien d'autre que de renvoyer un fichier BottomSheetDialog
.
MISE À JOUR POUR ANDROIDX
Lors de l' utilisation AndroidX, la ressource trouvée précédemment à android.support.design.R.id.design_bottom_sheet
peut maintenant être trouvé à com.google.android.material.R.id.design_bottom_sheet
.
BottomSheetDialogFragment
impression que le comportement est saccadé (semble sauter des images dans l'animation d'ouverture) en passant du comportement réduit au comportement développé. Edit: Testé ceci sur les appareils Android Marshmallow et KitKatandroid.support.design.R
après la mise à jour des bibliothèques de support?android.support.design.R
, tout comme @natario. J'utiliseimplementation "com.google.android.material:material:1.0.0"
. J'utilise également AndroidX dans le projet.com.google.android.material.R.id.design_bottom_sheet
La réponse d'efeturi est excellente, cependant, si vous souhaitez utiliser onCreateView () pour créer votre BottomSheet, par opposition à onCreateDialog () , voici le code que vous devrez ajouter sous votre méthode 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); }
la source
Une solution simpliste et élégante:
BottomSheetDialogFragment
pourrait être sous-classée pour résoudre ce problème: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(com.google.android.material.R.id.design_bottom_sheet); BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); behavior.setSkipCollapsed(true); behavior.setState(BottomSheetBehavior.STATE_EXPANDED); } }); return bottomSheetDialog; } }
Alors étendez cette classe au lieu de
BottomSheetDialogFragment
créer votre propre feuille de fond.Remarque
Remplacez
com.google.android.material.R.id.design_bottom_sheet
parandroid.support.design.R.id.design_bottom_sheet
si votre projet utilise d'anciennes bibliothèques de support Android.la source
com.google.android.material.R
maintenant au lieu deandroid.support.design.R
.Je pense que ceux ci-dessus sont meilleurs. Malheureusement, je n'ai pas trouvé cette solution avant de l'avoir résolue. Mais écrivez ma solution. assez similaire à tous.
=================================================== =================================
Je suis confronté au même problème. C'est ce que j'ai résolu. Le comportement est masqué dans BottomSheetDialog, qui est disponible pour obtenir le comportement. Si vous ne souhaitez pas changer votre mise en page parente en CooridateLayout, vous pouvez essayer ceci.
ÉTAPE 1: personnalisez le 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 } }
ÉTAPE 2: faites étendre votre fragment à ce fragment personnalisé
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() } }
la source
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); } });
J'ai rencontré NullPointException
BottomSheetBehavior.from(bottomSheet)
card.findViewById(android.support.design.R.id.design_bottom_sheet)
renvoie null.C'est étrange. J'ajoute cette ligne de code à Watches dans Android Monitor en mode DEBUG et je l'ai trouvée renvoyer Framelayout normalement.
Voici le code de
wrapInBottomSheet
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; }
Parfois, j'ai trouvé que ce
R.id.design_bottom_sheet
n'est pas égal àandroid.support.design.R.id.design_bottom_sheet
. Ils ont une valeur différente dans différents R.java.Alors je change
android.support.design.R.id.design_bottom_sheet
pourR.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); } });
Plus de NullPointException maintenant.
la source
Appliquer l'
BottomsheetDialogFragment
état dansonResume
résoudra ce problème@Override public void onResume() { super.onResume(); if(mBehavior!=null) mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); }
onShow(DialogInterface dialog)
etpostDelayed
peut causer un problème d'animationla source
Tous les résultats avec l'utilisation de onShow () provoquent un bogue de rendu aléatoire lorsque le clavier virtuel est affiché. Voir la capture d'écran ci-dessous - La boîte de dialogue BottomSheet n'est pas au bas de l'écran mais est placée comme le clavier était affiché. Ce problème ne se produit pas toujours mais assez souvent.
MISE À JOUR
Ma solution avec reflet de membre privé est inutile. Utiliser postDelayed (avec environ 100 ms) pour créer et afficher une boîte de dialogue après masquer le clavier logiciel est une meilleure solution. Alors les solutions ci-dessus avec onShow () sont correctes.
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);
J'implémente donc une autre solution, mais cela nécessite l'utilisation de la réflexion, car BottomSheetDialog a tous les membres comme privés. Mais cela résout le bogue de rendu. La classe BottomSheetDialogFragment est uniquement AppCompatDialogFragment avec la méthode onCreateDialog qui crée BottomSheetDialog. Je crée mon propre enfant d'AppCompatDialogFragment qui crée ma classe étend BottomSheetDialog et qui résout l'accès au membre de comportement privé et le met dans la méthode onStart à l'état 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()); } .... }
la source
La manière la plus simple que j'ai implémentée est la suivante: Ici, nous trouvons android.support.design.R.id.design_bottom_sheet et définissons l'état de la feuille du bas comme EXPANDED .
Sans cela, ma feuille du bas était toujours bloquée dans l'état COLLAPSED si la hauteur de la vue est supérieure à 0,5 de la hauteur de l'écran et que je dois faire défiler manuellement pour afficher la feuille du bas complète.
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 source
Semblable à uregentx answer, dans kotlin , vous pouvez déclarer votre classe de fragment qui s'étend de
BottomSheetDialogFragment
, et lorsque la vue est créée, vous pouvez définir l'état par défaut de l'écouteur de boîte de dialogue après l'affichage de la boîte de dialogue.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 } }
N'oubliez pas d'utiliser l'implémentation de la conception matérielle dans gradle.
Jetez également un œil aux feuilles de fond de référence de conception de matériaux
la source
dialog?
variable dans onCreateView?dialog
est une propriété de la classeDialogFragment
, est en fait un Getter. Dans cet exemple, j'ai utilisé ce getter pour obtenir l'instance DialogFragment actuelle et y accédersetOnShowListener
. Peut-être avez-vous déjà utilisé ce type d'instructions dans votre projet, par exemple dans une activité, pour accéder à la barre d'actionactionBar
getter est utilisé, vous pouvez donc modifier ce composant, par exempleactionBar?.subtitle = "abcd"
Ma réponse est plus ou moins la même que la plupart des réponses ci-dessus avec une légère modification. Au lieu d'utiliser findViewById pour trouver d'abord la vue de bas de page, j'ai préféré ne pas coder en dur les identifiants de ressources de vue du cadre, car ils pourraient changer à l'avenir.
setOnShowListener(dialog -> { BottomSheetBehavior bottomSheetBehavior = ((BottomSheetDialog)dialog).getBehavior(); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); });
la source
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return super.onCreateDialog(savedInstanceState).apply { setOnShowListener { (this@TipsBottomDialogFragment.dialog as BottomSheetDialog).behavior.setState( BottomSheetBehavior.STATE_EXPANDED ) } } }
la source
Postez ceci ici aux futurs lecteurs, car je pense que nous pouvons utiliser une autre solution.
J'essayais de résoudre le même problème que vous avez décrit avec un
BottomSheetDialog
.Je n'aime pas utiliser les identifiants Android internes et je viens de
BottomSheetDialog
getBehavior
découvrir qu'il existe une méthode à l'intérieur que vous pouvez utiliser:Vous pouvez l'utiliser dans votre
BottomSheetDialog
:behavior.state = BottomSheetBehavior.STATE_EXPANDED
En utilisant,
BottomSheetDialogFragment
vous pouvez faire la même conversion de la boîte de dialogue de ce DialogFragment versBottomSheetDialog
.la source
BottomSheetDialogFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED }
ou lorsque vous êtes prêt à montrer:
private fun onContentLoaded(items: List<Any>) { adapter.submitList(items) (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED }
la source
Dans votre classe Kotlin BottomSheetDialogFragment, remplacez onCreateDialog comme ci-dessous
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val bottomSheetDialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog bottomSheetDialog.setOnShowListener { val bottomSheet = bottomSheetDialog.findViewById<FrameLayout>( com.google.android.material.R.id.design_bottom_sheet ) val behavior = BottomSheetBehavior.from(bottomSheet!!) behavior.skipCollapsed = true behavior.state = BottomSheetBehavior.STATE_EXPANDED } return bottomSheetDialog }
la source