web-dev-qa-db-fra.com

Définir l'état de BottomSheetDialogFragment sur développé

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);  
59
user2560886

"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.

144
efemoney

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);
}
24
goodKode

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.

5
DYS

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

3
John Ruban Singh
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.

2
legendmohe

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()
   }
}
2
盧誼玲

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
    }
}
1
Akhil

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.

enter image description here

[~ # ~] 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());
    }

    ....
}
1
Petr Daňa

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

0
FJCG