Définir l'état de BottomSheetDialogFragment à expanded
comment définir l'état d'extension d'un fragment BottomSheetDialogFragment
l'élargissement de l'aide BottomSheetBehavior#setState(STATE_EXPANDED)
utilisation de la bibliothèque de conception de Support Android (v23.2.1)?
https://code.google.com/p/android/issues/detail?id=202396 dit:
les feuilles du bas sont réglées à STATE_COLLAPSED au début. Appelez BottomSheetBehavior#setState (STATE_EXPANDED) si vous voulez l'étendre. Notez que vous ne pouvez pas appeler la méthode avant les layouts de vue.
le pratique suggérée nécessite une vue pour être gonflée en premier, mais je ne suis pas sûr comment je vais mettre le comportement Bottomsheet sur un fragment (BottomSheetDialogFragment
).
View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
7 réponses
"notez que vous ne pouvez pas appeler la méthode avant les layouts de vue."
Le texte ci-dessus est l'indice.
les dialogues ont un écouteur qui est activé une fois que la boîte de dialogue est . Le dialogue ne peut pas être affiché s'il n'est pas affiché.
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), appel:
// 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
se révèle ê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;
}
}
Laissez-moi savoir si cela aide.
UPDATE
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);
}
});
// Do something with your dialog like setContentView() or whatever
return dialog;
}
}
mais je ne vois vraiment pas pourquoi quelqu'un voudrait faire cela comme la base BottomSheetFragment
ne rien faire d'autre que de retourner un BottomSheetDialog
.
la réponse d'efeturi est excellente, cependant, si vous voulez utiliser onreateview () pour créer votre BottomSheet, par opposition à aller avec onreatedialog (), voici le code à ajouter dans votre onreateview () 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 cela:
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;
}
}
donc étendre cette classe au lieu de BottomSheetDialogFragment
pour créer votre propre feuille inférieure.
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)
parce que d.findViewById(android.support.design.R.id.design_bottom_sheet)
renvoie la valeur null.
C'est étrange. J'ajoute cette ligne de code aux montres sur Android Monitor en mode déboguage et je l'ai trouvé renvoie Framelayout normalement.
voici le code de wrapInBottomSheet
in 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;
}
de temps en temps, 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.
alors je change android.support.design.R.id.design_bottom_sheet
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);
}
});
plus de NullPointException maintenant.
Appliquer BottomsheetDialogFragment état dans OnResume permettra de résoudre ce problème
@Override
public void onResume() {
super.onResume();
if(mBehavior!=null)
mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
onShow (DialogInterface dialog) et postDelayed peuvent causer un bug d'animation
tous les résultats avec l'utilisation de onShow() provoquent un bug de rendu aléatoire lorsque le clavier doux est affiché. Voir la capture d'écran la boîte de dialogue de bellow - BottomSheet n'est pas en bas de l'écran mais est placée comme le clavier était affiché. Ce problème se produit pas toujours, mais assez souvent.
UPDATE
ma solution avec le reflet de député est inutile. Utiliser postDelayed (avec environ 100 ms) pour créer et montrer dialogue après masquer le clavier virtuel est la 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);
donc j'implémente une autre solution, mais il faut utiliser la réflexion, parce que BottomSheetDialog a tous les membres comme privé. Mais ça résout le problème du rendu. La classe BottomSheetDialogFragment est seulement AppCompatDialogFragment avec la méthode onCreateDialog qui crée BottomSheetDialog. Je crée propre enfant de AppCompatDialogFragment qui crée ma classe s'étend BottomSheetDialog et qui résout l'accès au comportement privé membre et le met dans la méthode onStart à STATE_EXPANDED state.
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 façon la plus facile que j'ai mis en œuvre est comme ci-dessous, Ici nous trouvons android.support.design.R. id.design_bottom_sheet and setting bottom sheet state as EXPANDED.
sans cela, ma feuille du bas a toujours été coincé dans L'état effondré si la hauteur de vue est supérieure à 0,5 de la hauteur de l'écran et je dois faire défiler manuellement pour voir la pleine feuille du bas.
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
}
}