material-components / material-components-android

Modular and customizable Material Design UI components for Android
Apache License 2.0
16.37k stars 3.07k forks source link

[BottomSheetDialogFragment] What's the recommended way to customize the behavior of a BottomSheetDialogFragment? #1034

Closed renanferrari closed 3 years ago

renanferrari commented 4 years ago

Let's say I want my bottom sheet to skip its collapsed state. If I used a BottomSheetBehavior I could just set skipCollapse to true. What's the recommended way to achieve that on a BottomSheetDialogFragment?

So far, I've been retrieving and modifying the BottomSheetDialogFragment's inner BottomSheetBehavior myself, like so:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        dialog?.setOnShowListener { dialogInterface ->
            val sheetDialog = dialogInterface as? BottomSheetDialog

            val bottomSheet = sheetDialog?.findViewById<FrameLayout>(
                    com.google.android.material.R.id.design_bottom_sheet
            )

            bottomSheet?.let {
                val behavior = BottomSheetBehavior.from(it)
                behavior.skipCollapsed = true
                // any other behavior modification here
            }
        }
    }

However, this approach seems kind of hackish to me. Is there any alternative or is this the recommended way to achieve what I want?

AradiPatrik commented 4 years ago

I think you can set it in xml using app:behavior_skipCollapsed="true" Also in situations where such an xml attribute is not available, using BindingAdapters can help hide the "hackish" implementation details. Here you can find the full list of xml attributes you can use to customize bottomsheet behavior: https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/bottomsheet/res/values/attrs.xml

renanferrari commented 4 years ago

@AradiPatrik Thank you, but I don't believe your answer addresses the main point of my question.

My question was specific to BottomSheetDialogFragment, so XML attributes are unavailable. I'm also not looking for ways to "hide" the details of my implementation.

I just want to understand, from the perspective of the maintainers of this library, what's the recommended way to achieve what I need in the context I have described.

syt0r commented 4 years ago

I facing same problem, are behavior attrs cannot be configured via xml for BottomSheetDialogFragment?

renanferrari commented 4 years ago

@SYtor Nope, it uses the default ones and you can only access/change them programmatically, like shown in my original post.

iRYO400 commented 4 years ago

I've found a convenient way to config bottom sheet behavior using styles.

  1. Customize default BottomSheet by overriding it's attributes, for example in styles.xml
    <style name="Widget.MyApp.BottomSheet.Modal" parent="Widget.MaterialComponents.BottomSheet.Modal">
        <item name="behavior_skipCollapsed">true</item>
        <item name="behavior_fitToContents">true</item>
        <item name="behavior_peekHeight">1000dp</item> // yep, that helped to skip collapsed state at initial
        <item name="behavior_hideable">true</item>
    </style>

Go inside Widget.MaterialComponents.BottomSheet.Modal to see what settings you can modify.

  1. Then create custom theme inherited from Theme.Design.BottomSheetDialog and set that you want to override bottom sheet's style with you own. Also can be placed in styles.xml
    <style name="Theme.MyApp.BottomSheetDialog" parent="Theme.Design.BottomSheetDialog">
        <item name="bottomSheetStyle">@style/Widget.MyApp.BottomSheet.Modal</item>
    </style>
  1. And the last, define your new created theme for bottom sheet dialog in your Activity's theme or Application's theme, which placed in themes.xml(hope you follow Google's recommendations about packaging styles&themes)
    <style name="Base.Theme.MyApp" parent="Base.Theme.Root">
    ... too many other things
    <item name="bottomSheetDialogTheme">@style/Theme.MyApp.BottomSheetDialog</item>
    </style>
iRYO400 commented 4 years ago

@SYtor @renanferrari checkout my previous comment

P.S. I'm using the latest stable version of MaterialDesign dependency com.google.android.material:material:1.1.0

xanscale commented 4 years ago

@renanferrari inside onViewCreated i used that

val behavior: BottomSheetBehavior<*> = (dialog as BottomSheetDialog).behavior
behavior.halfExpandedRatio = 0.3f
behavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED

i don't know if it is the correct way

Papashkin commented 3 years ago

@renanferrari seems It's possible to customize behavior as in the following code:

val callback = object : BottomSheetBehavior.BottomSheetCallback() {
     override fun onStateChanged(bottomSheet: View, newState: Int) {
          onStateChanged(binding, newState)
     }

     override fun onSlide(bottomSheet: View, slideOffset: Float) {
          onSlide(binding, slideOffset)
     }
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val behavior: BottomSheetBehavior<*> = (dialog as BottomSheetDialog).behavior
        behavior.addBottomSheetCallback(behaviorCallback)
        ...
}

Thanks to @xanscale for the idea.

DmitryTankovich commented 3 years ago

@renanferrari Google use this xml to create a dialog inside BottomSheetDialogFragment https://github.com/dandar3/android-support-design/blob/master/res/layout/design_bottom_sheet_dialog.xml

you can try to overwrite @string/bottom_sheet_behavior, just add this to your resources: <string name="bottom_sheet_behavior" translatable="false">your.custom.Behavior</string>

drchen commented 3 years ago

I think the way @xanscale posted is the recommended way from a library maintainer's perspective.

The solution @DmitryTankovich posted should also work but it's less recommended since it's fragile and can be easily broken by an internal change.

I'll close the issue. Let us know if you have more questions. : )

ipanamski commented 1 year ago

The following code called from onCreateView ((BottomSheetDialog) getDialog()).getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED); Seems to work fine for me.