0

This question may seem a little bit odd, but let me explain my problem.

I have a BottomSheetDialogFragment with rounded top corners. When I fully expand my dialog those corners will be filled automatically. I want the height to be more or less fixed, so isFitToContents is set to false.

Preferably I want my expanded state to have a slight margin to the top and still transparent corners, so the user is able to see a bit of the underlying layout. STATE_HALF_EXPANDED with a halfExpandedRatio of something like 0.95 is pretty much it. But then the user is still able to switch to STATE_EXPANDED with a swipe up, which is weird, because there is almost no difference in height between both states, so this seems unnecessary.

Is there a way to make STATE_HALF_EXPANDED the maximum (disable STATE_EXPANDED) or, as an alternative, can I make STATE_EXPANDED behave as described and skip STATE_HALF_EXPANDED instead?

It seems like a really small thing, but I didn't find a way to achieve this behavior yet.

(I'm using XML layouts if this is relevant.)


This is what I currently apply to the dialog in the onShowListener:

isFitToContents = false
halfExpandedRatio = 0.95f
state = BottomSheetBehavior.STATE_HALF_EXPANDED
skipCollapsed = true

And in onViewCreated I ensure the parent layout's height is MATCH_PARENT, so the area below my inflated layout is not transparent:

val parentLayout = dialog?.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
parentLayout?.layoutParams?.height = ViewGroup.LayoutParams.MATCH_PARENT

This is the maximum state that I want

This is the state I want to disable

Sumit Singh
  • 487
  • 5
  • 19
keplusplus
  • 16
  • 3

2 Answers2

0

You can use following function in your bottom sheet, this may helpful for your problem.

override onCreateDialog()

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState)
        dialog.setOnShowListener { dialogInterface: DialogInterface ->
            val bottomSheetDialog = dialogInterface as BottomSheetDialog
            setupFullHeight(bottomSheetDialog)
        }
        return dialog
    }

copy this function :

private fun setupFullHeight(bottomSheetDialog: BottomSheetDialog) {
        val bottomSheet = bottomSheetDialog.findViewById<FrameLayout>(R.id.design_bottom_sheet)
        //BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        if (bottomSheet != null) {
            val layoutParams = bottomSheet.layoutParams
            val windowHeight = windowHeight
            if (layoutParams != null) {
                layoutParams.height = windowHeight
            }
            bottomSheet.layoutParams = layoutParams
            BottomSheetBehavior.from(bottomSheet).setPeekHeight((windowHeight * 0.8).toInt(), _do)
        }
    }

EDITED - Missed variable updated.

private val windowHeight: Int
        get() = if (activity != null && !requireActivity().isDestroyed && !requireActivity().isFinishing) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                val windowMetrics = requireActivity().windowManager.currentWindowMetrics
                val insets = windowMetrics.windowInsets
                    .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
                windowMetrics.bounds.height() - insets.top - insets.bottom
            } else {
                val displayMetrics = DisplayMetrics()
                @Suppress("DEPRECATION")
                requireActivity().windowManager
                    .defaultDisplay.getMetrics(displayMetrics)
                displayMetrics.heightPixels
            }
        } else 0
Kishan Mevada
  • 662
  • 1
  • 6
  • 17
  • So the key thing that you are suggesting is `setPeekHeight` on the `BottomSheetBehavior`? As far as I understand this would affect the height of the collapsed state, which is skipped in my dialog (`skipCollapsed = true`). Beyond that you are setting the height of the parent `FrameLayout`, which is, in my case, set to `MATCH_PARENT`. I believe this is correct for my case. The assignment `val windowHeight = windowHeight` is an error for me, what is the second `windowHeight` referencing to? – keplusplus Aug 29 '22 at 11:25
  • Answer updated, hope it helps. – Kishan Mevada Aug 29 '22 at 11:40
0

I found a soulution which uses STATE_EXPANDED as the only available state, since I finally managed to keep the rounded corners clear/transparent in that state.

Originally I was just cutting out the corners using this ShapeAppearance,

<style name="ShapeAppearance.App.LargeComponent" parent="ShapeAppearance.MaterialComponents.LargeComponent">
    <item name="cornerFamily">rounded</item>
    <item name="cornerSize">32dp</item>
</style>

which I then applied to the BottomSheet.Modal style. Instead I now set the whole background of the BottomSheetDialogFragment transparent, what I couldn't accomplish before. But now it works using the following styles:

<style name="BottomSheetDialogThemeOverlay" parent="ThemeOverlay.MaterialComponents.BottomSheetDialog">
    <item name="bottomSheetStyle">@style/BottomSheetDialogStyle</item>
</style>

<style name="BottomSheetDialogStyle" parent="Widget.MaterialComponents.BottomSheet.Modal">
    <item name="backgroundTint">@color/transparent</item>
</style>

Obviously you need to apply them to you AppTheme using this line:

<item name="bottomSheetDialogTheme">@style/BottomSheetDialogThemeOverlay</item>

Then I was able to add a proper drawable with rounded corners as background inside the dialog's layout.


Final behavior setup

To make STATE_EXPANDED the initial and only available state to the dialog I use the following code inside onCreateView:

dialog?.setOnShowListener { dialogInterface ->
    val bottomSheetDialog = dialogInterface as BottomSheetDialog
    bottomSheetDialog.behavior.apply {

        isFitToContents = false
        skipCollapsed = true

        expandedOffset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48f, resources.displayMetrics).toInt()
        // Just using Int (pixel value) would be fine here, but I prefer dp

        state = BottomSheetBehavior.STATE_EXPANDED
    }
}

And additionally I need to override onViewCreated to achieve match_parent in my dialog root layout's height behaving as it should:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val parent = dialog?.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
    parent?.layoutParams?.height = ViewGroup.LayoutParams.MATCH_PARENT
}

That's all I needed to achieve the behavior described in my question.

keplusplus
  • 16
  • 3