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);  
41
demandé sur user2560886 2016-03-11 13:16:03

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.

88
répondu efemoney 2018-09-06 14:38:43

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);
}
13
répondu goodKode 2016-04-15 16:12:48

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.

3
répondu DYS 2017-11-24 09:21:25
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_sheetR.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.

2
répondu legendmohe 2016-05-27 01:48:42

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

2
répondu John Ruban Singh 2017-11-20 07:16:03

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.

enter image description here

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());
    }

    ....
}
0
répondu Petr Daňa 2017-04-03 13:32:53

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
    }
}
0
répondu Akhil 2018-01-09 11:44:58