Set state of BottomSheetDialogFragment to expanded

前端 未结 14 760
有刺的猬
有刺的猬 2020-11-30 19:11

How do you set the state of a fragment extending BottomSheetDialogFragment to expanded using BottomSheetBehavior#setState(STATE_EXPANDED) using the

相关标签:
14条回答
  • 2020-11-30 19:37

    BottomSheetDialogFragment:

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

    or when ready to show:

    private fun onContentLoaded(items: List<Any>) {
        adapter.submitList(items)
        (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED
    }
    
    0 讨论(0)
  • 2020-11-30 19:42
    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);
                }
            });
    

    I met NullPointException in BottomSheetBehavior.from(bottomSheet) because d.findViewById(android.support.design.R.id.design_bottom_sheet) returns null.

    It's strange. I add this line of code to Watches in Android Monitor in DEBUG mode and found it return Framelayout normally.

    Here's code of 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;
        }
    

    Occasionally, I found that R.id.design_bottom_sheet is not equal to android.support.design.R.id.design_bottom_sheet. They have different value in different 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.

    0 讨论(0)
  • 2020-11-30 19:43

    efeturi's answer is great, however, if you want to use onCreateView() to create your BottomSheet, as opposed to going with onCreateDialog(), here is the code you will need to add under your 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);
    }
    
    0 讨论(0)
  • 2020-11-30 19:43

    My answer is more or less same as most of the above answers with a slight modification. Instead of using findViewById to first find the bottom sheet view, I have preferred not to hardcode any framework view resource ids since they might change in future.

    setOnShowListener(dialog -> {
                BottomSheetBehavior bottomSheetBehavior = ((BottomSheetDialog)dialog).getBehavior();
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            });
    
    0 讨论(0)
  • 2020-11-30 19:44

    The easiest way I implemented is as below, Here we are finding android.support.design.R.id.design_bottom_sheet and setting bottom sheet state as EXPANDED.

    Without this, my bottom sheet was always stuck in the COLLAPSED state if view height is more than 0.5 of screen height and I have to manually scroll to view full bottom sheet.

    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 讨论(0)
  • 2020-11-30 19:49

    Similar to uregentx answer, in kotlin, you can declare your fragment class that extends from BottomSheetDialogFragment, and when the view is created you can set the dialog listener default state after the dialog is displayed.

    STATE_COLLAPSED: The bottom sheet is visible but only showing its peek height.

    STATE_EXPANDED: The bottom sheet is visible and its maximum height.

    STATE_HALF_EXPANDED: The bottom sheet is visible but only showing its half height.

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

    Remember using material design implementation in gradle.

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

    Also take a look to material design reference Bottom Sheets

    0 讨论(0)
提交回复
热议问题