Comment définir l'état d'un fragment qui étend BottomSheetDialogFragment
à développer à l'aide de BottomSheetBehavior#setState(STATE_EXPANDED)
à l'aide de Android Support Design Library (v23.2.1)?
https://code.google.com/p/Android/issues/detail?id=202396 dit:
Les feuilles de fond sont d'abord définies sur STATE_COLLAPSED. Appelez BottomSheetBehavior # setState (STATE_EXPANDED) si vous souhaitez le développer. Notez que vous ne pouvez pas appeler la méthode avant les dispositions de vue.
La pratique suggérée nécessite que la vue soit gonflée en premier, mais je ne suis pas sûr de savoir comment définir le BottomSheetBehaviour sur un fragment (BottomSheetDialogFragment
).
View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
"Notez que vous ne pouvez pas appeler la méthode avant les dispositions de vue."
Le texte ci-dessus est l'indice.
Les dialogues ont un écouteur qui est déclenché une fois que le dialogue est affiché. La boîte de dialogue ne peut pas être affichée si elle n'est pas présentée.
Ainsi, dans la onCreateDialog()
de votre feuille de fond modale (BottomSheetFragment
), juste avant de renvoyer la boîte de dialogue (ou n'importe où, une fois que vous avez une référence à la boîte de dialogue), appelez:
// 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);
}
});
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 aide.
MISE À JOUR
Notez que vous pouvez également remplacer BottomSheetDialogFragment
par:
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;
}
}
Mais je ne vois vraiment pas pourquoi quelqu'un voudrait faire cela car la base BottomSheetFragment
ne fait rien d'autre que renvoyer un BottomSheetDialog
.
MISE À JOUR POUR ANDROIDX
Lorsque vous utilisez AndroidX, la ressource précédemment trouvée à l'adresse Android.support.design.R.id.design_bottom_sheet
peut maintenant être trouvé à com.google.Android.material.R.id.design_bottom_sheet
.
la réponse de efeturi est excellente, cependant, si vous souhaitez utiliser onCreateView () pour créer votre BottomSheet, par opposition à l'utilisation de onCreateDialog () , voici le code que vous devrez ajouter sous votre onCreateView () méthode:
@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);
}
J'ai écrit une sous-classe de BottomSheetDialogFragment
pour gérer ceci:
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(com.google.Android.material.R.id.design_bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setSkipCollapsed(true);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
});
return bottomSheetDialog;
}
}
Donc, étendez cette classe au lieu de BottomSheetDialogFragment
pour créer votre propre feuille de fond.
Changement com.google.Android.material.R.id.design_bottom_sheet
à Android.support.design.R.id.design_bottom_sheet
_ si votre projet utilise d’anciennes Android bibliothèques de support.
Appliquer l’état BottomsheetDialogFragment dans OnResume résoudra ce problème.
@Override
public void onResume() {
super.onResume();
if(mBehavior!=null)
mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
onShow (dialogue DialogInterface) et postDelayed peuvent causer des problèmes d'animation
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 dans BottomSheetBehavior.from(bottomSheet)
parce que d.findViewById(Android.support.design.R.id.design_bottom_sheet)
renvoie null.
C'est étrange. J'ajoute cette ligne de code à Watches dans Android Surveillez en mode DEBUG et le trouve retourné Framelayout normalement.
Voici le code de wrapInBottomSheet
dans 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 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.
Je change donc Android.support.design.R.id.design_bottom_sheet
En 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);
}
});
Pas plus NullPointException maintenant.
Je pense que ceux ci-dessus est mieux. Malheureusement, je n'ai pas trouvé cette solution avant d'avoir résolu le problème. Mais écris ma solution. assez semblable à 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 souhaitez ne pas modifier la présentation de votre parent en CooridateLayout, vous pouvez essayer ceci.
ÉTAPE 1: personnaliser 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: faire en sorte que votre fragment étende 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()
}
}
Le moyen le plus simple que j'ai mis en œuvre est le suivant. Nous trouvons ici Android.support.design.R.id.design_bottom_sheet et définir le dernier état de la feuille comme DÉVELOPPÉ .
Sans cela, ma feuille de fond était toujours bloquée à l'état COLLAPSED si la hauteur de vue est supérieure à 0,5 fois la hauteur de l'écran et que je dois faire défiler manuellement pour voir la page de fond 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
}
}
Tous les résultats obtenus avec 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 ne se trouve 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.
[~ # ~] met à jour [~ # ~]
Ma solution avec réflexion du député n'est pas nécessaire. Utiliser postDelayed (avec environ 100 ms) pour créer et afficher des dialogues après le masquage du clavier logiciel est la meilleure solution. Ensuite, les solutions ci-dessus avec onShow () sont acceptables.
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 elle nécessite l'utilisation de la réflexion, car BottomSheetDialog a tous les membres comme privés. Mais cela résout le bug de rendu. La classe BottomSheetDialogFragment est uniquement AppCompatDialogFragment avec la méthode onCreateDialog qui crée BottomSheetDialog. Je crée mon propre enfant de AppCompatDialogFragment qui crée ma classe et étend BottomSheetDialog et résout l'accès au membre de comportement privé et le définit 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());
}
....
}
Similaire à uregentx, en kotlin , vous pouvez déclarer votre classe de fragments allant de BottomSheetDialogFragment
et lorsque la vue est créée, vous pouvez définir l’état par défaut de l’écouteur de la boîte de dialogue une fois celle-ci affichée.
STATE_COLLAPSED: la feuille du bas est visible mais ne montre que sa hauteur de coup d'oeil.
STATE_EXPANDED: La feuille du bas est visible et sa hauteur maximale.
STATE_HALF_EXPANDED: La feuille du bas est visible mais ne montre que sa demi-hauteur.
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 la mise en œuvre matérielle dans Gradle.
implementation "com.google.Android.material:material:$version"
Jetez également un œil à la référence de conception de matériau Bottom Sheets