代码之家  ›  专栏  ›  技术社区  ›  user2560886

将BottomSheetDialogFragment的状态设置为已展开

  •  143
  • user2560886  · 技术社区  · 9 年前

    如何设置扩展的片段的状态 BottomSheetDialogFragment 使用扩展 BottomSheetBehavior#setState(STATE_EXPANDED) 使用Android Support Design Library(v23.2.1)?

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

    底部板材首先设置为STATE_COLLAPSED。如果要展开,请调用BottomSheetBehavior#setState(STATE_EXPANDED)。请注意,不能在查看布局之前调用该方法。

    这个 suggested practice 需要先放大视图,但我不确定如何将BottomSheetBehaviour设置为片段( 底部工作表对话框片段 ).

    View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);  
    BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);  
    
    20 回复  |  直到 9 年前
        1
  •  282
  •   Rahul    4 年前

    “请注意,在查看布局之前不能调用该方法。”

    以上文字就是线索。

    对话有一个监听器,一旦对话被触发 展示 。如果没有布局,则无法显示对话框。

    所以,在 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;
        }
    }
    

    如果有帮助,请告诉我。

    更新

    请注意,您还可以覆盖 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;
        }
    }
    

    但我真的不明白为什么有人会想把它作为基础 底部工作表片段 除了返回 BottomSheetDialog .

    ANDROIDX更新

    使用AndroidX时,以前在 android.support.design.R.id.design_bottom_sheet 现在可以在 com.google.android.material.R.id.design_bottom_sheet .

        2
  •  55
  •   goodKode    9 年前

    然而,如果您想使用,efeturi的答案很好 打开创建视图() 创建BottomSheet,而不是使用 onCreateDialog() ,这是您需要在 打开创建视图() 方法:

    @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);
    }
    
        3
  •  29
  •   DYS    4 年前

    简单而优雅的解决方案:

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

    所以扩展这个类,而不是 底部工作表对话框片段 创建自己的底片。

    笔记

    改变 com.google.android.material.R.id.design_bottom_sheet android.support.design.R.id.design_bottom_sheet 如果您的项目使用旧的Android支持库。

        4
  •  11
  •   Yeldar Nurpeissov    4 年前

    底部工作表对话框片段 :

    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
    }
    
        5
  •  11
  •   lasec0203    4 年前

    我认为上面的那些更好。 可悲的是,在我解决问题之前,我没有找到解决方案。 但写下我的解决方案。非常类似。

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

    我也面临同样的问题。 这就是我解决的问题。 行为隐藏在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()
       }
    }
    
        6
  •  8
  •   Ajay Mourya    4 年前

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

    (dialog as BottomSheetDialog).behavior.state = BottomSheetBehavior.STATE_EXPANDED
    
        7
  •  5
  •   prateek    5 年前

    我的答案与上述大多数答案大致相同,只是稍作修改。与其使用findViewById首先查找底部工作表视图,我更希望不要硬编码任何框架视图资源ID,因为它们将来可能会更改。

    setOnShowListener(dialog -> {
                BottomSheetBehavior bottomSheetBehavior = ((BottomSheetDialog)dialog).getBehavior();
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            });
    
        8
  •  5
  •   leigo    5 年前
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return super.onCreateDialog(savedInstanceState).apply {
            setOnShowListener {
                (this@TipsBottomDialogFragment.dialog as BottomSheetDialog).behavior.setState(
                    BottomSheetBehavior.STATE_EXPANDED
                )
            }
        }
    }
    
        9
  •  5
  •   culebrins    4 年前

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

    我正试图解决你用 BottomSheetDialog .

    我不喜欢使用内部Android ID,我刚刚发现里面有一个方法 底部工作表对话框 getBehavior 您可以使用:

    你可以在你的 底部工作表对话框 :

    behavior.state = BottomSheetBehavior.STATE_EXPANDED

    使用 BottomSheetDialogFragment 您可以将对话框从该DialogFragment强制转换为 底部工作表对话框 .

        10
  •  4
  •   legendmohe    9 年前
    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);
                }
            });
    

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

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

    这是的代码 wrapInBottomSheet 在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;
        }
    

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

    所以我改变了 android.support.design.R.id.design_bottom_sheet R、 id设计_底部_表 .

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

    现在不再有NullPointException。

        11
  •  4
  •   Emad Razavi Berkay92    4 年前

    在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
        }
    
        12
  •  4
  •   artenson.art98    3 年前

    您可以执行以下操作(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
    }
    
        13
  •  3
  •   John Ruban Singh    5 年前

    申请 BottomsheetDialogFragment 状态 onResume 将解决此问题

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

    onShow(DialogInterface dialog) postDelayed 可能导致动画问题

        14
  •  3
  •   Rahul Gaur Ziad Gholmish    5 年前

    类似 乌雷根特 答案,在 科特林牌手表 ,您可以声明从 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
        }
    }
    

    记住在渐变中使用材质设计实现。

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

    另请参阅材料设计参考 Bottom Sheets

        15
  •  3
  •   Rahul    4 年前

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

    enter image description here

    更新

    我的私人成员反映的解决方案是不必要的。隐藏软键盘后,使用postDelayed(大约100毫秒)创建和显示对话框是一个更好的解决方案。然后将上述解决方案与 显示() 没有问题。

    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类仅是使用onCreateDialog方法创建BottomScheetDiaog的AppCompatDialogFragment。我创建了自己的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());
        }
    
        ....
    }
    
        16
  •  3
  •   Jan Kotas    3 年前

    这是一个非常简洁的Kotlin解决方案,效果非常好。

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply {
            setOnShowListener {
               behavior.state = BottomSheetBehavior.STATE_EXPANDED
            }
        }
    }
    
        17
  •  1
  •   Akhil    7 年前

    我实现的最简单方法如下: android.support.design.R.id.design_bottom_sheet 并将底部页状态设置为 扩大 .

    没有这个,我的底片 一直处于崩溃状态 如果视图高度大于屏幕高度的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
        }
    }
    
        18
  •  1
  •   Ali Sidhu    3 年前

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

    (dialog as BottomSheetDialog).behavior.state = 
        BottomSheetBehavior.STATE_EXPANDED
    
        19
  •  0
  •   pravingaikwad07    2 年前

    简单答案(Kotlin+片段+bottomSheetDialogViewBinding):

    val bsd = BottomSheetDialog(requireContext())
    val bsdBinding = DialogBottomSheetViewBinding.inflate(LayoutInflater.from(requireContext()))
    bsd.behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    
        20
  •  -1
  •   Dominique    4 年前

    这就是我的工作原理,基于下面链接的回复。

    behavior = BottomSheetBehavior.from(bottomSheet1);
    if(action.equals("post") ) {
        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
        behavior.setDraggable(false); // disable dragging
    }
    

    enter link description here