将BottomSheetDialogFragment的状态设为已展开。

144 人关注

如何使用Android支持设计库(v23.2.1)将扩展 BottomSheetDialogFragment 的片段的状态设置为使用 BottomSheetBehavior#setState(STATE_EXPANDED) 展开?

https://code.google.com/p/android/issues/detail?id=202396 说。

底部页面一开始被设置为STATE_COLLAPSED。如果你想展开它,就调用BottomSheetBehavior#setState(STATE_EXPANDED)。注意,你不能在视图布局之前调用该方法。

The 建议的做法 要求先对视图进行充气,但我不确定如何将BottomSheetBehaviour设置到一个片段上( BottomSheetDialogFragment )。

View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);  
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);  
    
android
android-fragments
android-support-library
android-support-design
user2560886
user2560886
发布于 2016-03-11
20 个回答
efemoney
efemoney
发布于 2021-07-05
已采纳
0 人赞同

"注意,你不能在视图布局之前调用该方法。"

上面的文字就是线索。

对话框有一个监听器,一旦对话框被触发,它就会被触发。 shown .如果没有布置好,对话就无法显示。

因此,在你的模态底层表单的 onCreateDialog() 中( BottomSheetFragment ),就在返回对话框之前(或任何地方,一旦你有对对话框的引用),调用。

// 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);

在我的案例中,我的自定义BottomSheet变成了。

@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;

Let me know if this helps.

注意,你也可以把BottomSheetDialogFragment覆盖为。

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;

但我真的不明白为什么有人会想这么做,因为基础的BottomSheetFragment除了返回一个BottomSheetDialog外,并没有做任何事情。

更新 FOR ANDROIDX

当使用AndroidX时,以前在android.support.design.R.id.design_bottom_sheet找到的资源现在可以在com.google.android.material.R.id.design_bottom_sheet找到。

谢谢,我试过这个方法。它使 BottomSheetDialogFragment 在从折叠到展开的过程中显得很生硬(似乎在打开的动画中跳帧)。 编辑:在Android Marshmallow和KitKat设备上测试了这个方法
它对我来说是完美的。没有跳过。除了返回一个对话框外,你还做了其他什么吗?如果你用你的代码更新你的帖子,我将非常感激,这样我就能有一个更好的想法。
是不是只有我在更新支持库后才会出现找不到包 android.support.design.R 的情况?
我在解决 android.support.design.R 方面也有问题,就像@natario .我正在使用 implementation "com.google.android.material:material:1.0.0" 。我也在项目中使用AndroidX。
当使用AndroidX时,该资源可以在 com.google.android.material.R.id.design_bottom_sheet 找到。
goodKode
goodKode
发布于 2021-07-05
0 人赞同

efeturi的回答很好,但是,如果你想用 onCreateView() 来创建你的BottomSheet,而不是用 onCreateDialog() ,这里是你需要添加到你的 onCreateView() method:

@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);
    
或者,你根本不需要调用getDialog。我发现最干净的方法是同时覆盖onCreateView和onCreateDialog。在onCreateView中建立你的视图(就像你对任何片段一样),在onCreateDialog中完成对话框的代码(调用super.onCreateDialog来获取实例)
这拯救了我的一天。谢谢。
@Stimsoni onCreateView在使用onCreateDialog的情况下不被调用。 developer.android.com/reference/android/support/v4/app/...
Stimsoni
@Vincent_Paing,是的。在你所附的链接中,它说 "onCreateView不需要被实现"。它并没有说它不会被调用。请看一下这里的源代码 github.com/material-components/material-components-android/blob/... .默认的实现是调用onCreateDialog来创建底层页面,而上面的每一个解决方案仍然使用onCreateView,这意味着它们总是被调用。只要确保你仍然调用super.onCreateDialog(),如果你真的覆盖了它。
在BottomSheetDialogFragment中,它在onCreateView()中使我崩溃,我把它放在onViewCreated()中,它就完美了!谢谢你
DYS
DYS
发布于 2021-07-05
0 人赞同

一个简单而优雅的解决方案。

BottomSheetDialogFragment 可以被子类化以解决这个问题。

class NonCollapsableBottomSheetDialogFragment extends BottomSheetDialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
        dialog.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 dialog;

因此,扩展这个类而不是BottomSheetDialogFragment来创建你自己的底单。

如果你的项目使用旧的Android支持库,将com.google.android.material.R.id.design_bottom_sheet改为android.support.design.R.id.design_bottom_sheet

现在似乎是 com.google.android.material.R 而不是 android.support.design.R
DYS
@EpicPandaForce 当然,谷歌的Android团队最近重新包装了以前的支持库。
Yeldar Nurpeissov
Yeldar Nurpeissov
发布于 2021-07-05
0 人赞同

底层表格对话框片段 :

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED

或准备展示时。

private fun onContentLoaded(items: List<Any>) {
    adapter.submitList(items)
    (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED
    
这个解决方案对我来说非常有效。它是一个单行本,比以前的所有东西都简单得多。不知道为什么它没有得到更多的赞许......
Tina Lu
Tina Lu
发布于 2021-07-05
0 人赞同

我认为上面这些是更好的。 遗憾的是,在我解决这个问题之前,我没有找到这些解决方案。 但我写下了我的解决方案,与所有的解决方案都很相似。

==================================================================================

我也面临同样的问题。 这是我解决的问题。 该行为隐藏在BottomSheetDialog中,它可以用来获得该行为。 如果你不想把你的父布局改成CooridateLayout。 你可以试试这个。

第1步:定制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 = BottomSheetBehavior.STATE_EXPANDED

第2步:让你的片段扩展这个定制的片段

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()
    
Ajay Mourya
Ajay Mourya
发布于 2021-07-05
0 人赞同

在Kotlin中,在你的 BottomSheetDialogFragment onStart() 中添加以下一行

(dialog as BottomSheetDialog).behavior.state = BottomSheetBehavior.STATE_EXPANDED
    
在Kotlin中完美运行。简单而有效,应该得到更多的赞许。
0 人赞同

我的答案和上面的大多数答案差不多,只是稍作修改。我没有使用findViewById来寻找底层页面的视图,而是选择不硬编码任何框架视图资源的id,因为它们在未来可能会发生变化。

setOnShowListener(dialog -> {
            BottomSheetBehavior bottomSheetBehavior = ((BottomSheetDialog)dialog).getBehavior();
            bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    
leigo
leigo
发布于 2021-07-05
0 人赞同
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return super.onCreateDialog(savedInstanceState).apply {
        setOnShowListener {
            (this@TipsBottomDialogFragment.dialog as BottomSheetDialog).behavior.setState(
                BottomSheetBehavior.STATE_EXPANDED
    
culebrins
culebrins
发布于 2021-07-05
0 人赞同

在此发帖给未来的读者,因为我认为现在我们可以使用另一种解决方案。

我正试图用一个 BottomSheetDialog 来解决你描述的同样问题。

我不喜欢使用安卓内部的ID,我刚刚发现 BottomSheetDialog 里面有一个方法 getBehavior ,你可以使用。

你可以在你的 BottomSheetDialog 里面使用这个。

behavior.state = BottomSheetBehavior.STATE_EXPANDED

使用 BottomSheetDialogFragment ,你可以做同样的事情,将该DialogFragment中的对话框投递给 BottomSheetDialog

legendmohe
legendmohe
发布于 2021-07-05
0 人赞同
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);

我在BottomSheetBehavior.from(bottomSheet)中遇到NullPointException,因为d.findViewById(android.support.design.R.id.design_bottom_sheet)返回null。

这很奇怪。我在DEBUG模式下将这行代码添加到Android Monitor的Watches中,发现它正常返回Framelayout。

下面是BottomSheetDialog中wrapInBottomSheet的代码。

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;

偶尔,我发现R.id.design_bottom_sheet不等于android.support.design.R.id.design_bottom_sheet。它们在不同的R.java中具有不同的值。

So I change android.support.design.R.id.design_bottom_sheet to 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);

No more NullPointException now.

Emad Razavi
Emad Razavi
发布于 2021-07-05
0 人赞同

在你的Kotlin BottomSheetDialogFragment类中,覆盖onCreateDialog,如下所示

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
    
artenson.art98
artenson.art98
发布于 2021-07-05
0 人赞同

你可以做以下事情(Kotlin版本)。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    dialog?.let {
        val sheet = it as BottomSheetDialog
        sheet.behavior.state = BottomSheetBehavior.STATE_EXPANDED
    // rest of your stuff
    
Jan Kotas
Jan Kotas
发布于 2021-07-05
0 人赞同

这里有一个相当整洁的Kotlin解决方案,效果很好。

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply {
        setOnShowListener {
           behavior.state = BottomSheetBehavior.STATE_EXPANDED
    
John Ruban Singh
John Ruban Singh
发布于 2021-07-05
0 人赞同

BottomsheetDialogFragment 状态下应用 onResume 将解决这个问题。

@Override
public void onResume() {
    super.onResume();
    if(mBehavior!=null)
       mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);

替换代码3】和postDelayed可能导致动画故障

FJCG
FJCG
发布于 2021-07-05
0 人赞同

类似于 uregentx 回答,在 kotlin ,你可以声明你的扩展自 BottomSheetDialogFragment 的片段类,当视图被创建时,你可以在对话框显示后设置对话框监听器的默认状态。

state_collapsed:底部工作表是可见的,但只显示其偷看的

STATE_EXPANDED: 底片可见,其最大高度。

STATE_HALF_EXPANDED: 底部工作表是可见的,但只显示其一半的高度。 一半的高度。

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

记得在gradle中使用材料设计实现。

implementation "com.google.android.material:material:$version"

还可以看一下材料设计参考Bottom Sheets

onCreateView中的 dialog? 变量来自哪里?
FJCG
dialog DialogFragment 类的一个属性,实际上是一个获取器。在这个例子中,我使用这个getter来获取当前的DialogFragment实例,并对其进行 setOnShowListener 。 也许你已经在你的项目中使用了这种指令,例如在一个活动中,访问动作栏的 actionBar getter被使用,所以你可以修改那个组件,例如 actionBar?.subtitle = "abcd"
Petr Daňa
Petr Daňa
发布于 2021-07-05
0 人赞同

当软键盘显示时,使用onShow()的所有结果都会导致随机渲染错误。请看下面的截图--BottomSheet对话框不在屏幕的底部,而是像键盘显示的那样放置。这个问题并不总是发生,但经常发生。

我的解决方案中对私有成员的反射是不必要的。使用postDelayed(大约100毫秒)在隐藏软键盘后创建和显示对话框是一个更好的解决方案。那么,上述解决方案中的 onShow() 是可以的。

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

所以我实现了另一个解决方案,但它需要使用反射,因为BottomSheetDialog的所有成员都是私有的。但它解决了渲染错误。BottomSheetDialogFragment类只有AppCompatDialogFragment的onCreateDialog方法可以创建BottomSheetDialog。我创建了AppCompatDialogFragment的子类,它创建了我的类扩展BottomSheetDialog,解决了对私有行为成员的访问,并在onStart方法中设置为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());
    
Ali Sidhu
Ali Sidhu
发布于 2021-07-05
0 人赞同

在Kotlin中展开BottomSheet视图的简单解决方案。

(dialog as BottomSheetDialog).behavior.state = 
    BottomSheetBehavior.STATE_EXPANDED
    
Akhil
Akhil
发布于 2021-07-05
0 人赞同

我实施的最简单的方法如下,这里我们发现 android.support.design.R.id.design_bottom_sheet 并将底片状态设置为 扩容 .

Without this, my bottom sheet 总是停留在COLLAPSED状态。 如果视图高度超过屏幕高度的0.5,我必须手动滚动以查看完整的底部页面。

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
    
pravingaikwad07
pravingaikwad07
发布于 2021-07-05
0 人赞同

简单的答案(Kotlin + fragment + bottomSheetDialogViewBinding)。

val bsd = BottomSheetDialog(requireContext())
val bsdBinding = DialogBottomSheetViewBinding.inflate(LayoutInflater.from(requireContext()))
bsd.behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    
Vicente Domingos
Vicente Domingos
发布于 2021-07-05
0 人赞同

根据下面链接的答复,这对我来说是有效的。

behavior = BottomSheetBehavior.from(bottomSheet1);
if(action.equals("post") ) {