34

I am using BottomSheetDialogFragment in my activity, the dialog shows full height in portrait mode but doesn't when I switch to landscape mode.

Portrait Mode

Landscape Mode

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        CustomBottomSheetDialog customBottomSheetDialog = new CustomBottomSheetDialog();
        customBottomSheetDialog.show(getSupportFragmentManager(),customBottomSheetDialog.getTag());
    }
}

CustomBottomSheetDialog

public class CustomBottomSheetDialog extends BottomSheetDialogFragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return View.inflate(getContext(), R.layout.view_config, null);
    }
}

CustomBottomSheetDialog layout

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:background="#fdf107"
              android:layout_height="wrap_content">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="196dp"
        android:gravity="center"
        android:textColor="@color/colorAccent"
        android:text="BottomSheetDialogFragment"/>

</LinearLayout>

in landscape mode, i have to drag BottomSheetDialogFragment to see the whole content.

Gautam Chibde
  • 1,167
  • 3
  • 14
  • 27
  • 2
    Turns out it's intended behavior (https://issuetracker.google.com/issues/37083487). Quote "The Material Design guideline says that the bottom sheet should peek at the height with which the area above the bottom sheet is 19:6. Since your landscape screen is shorter than 16:9, it peeks at the minimum height in the spec." – Bracadabra Jan 09 '18 at 15:33
  • @Bracadabra I don't see the quote you are referring to. – clever_trevor Nov 26 '18 at 23:46
  • 1
    @clever_trevor it seems that comment was deleted. – Bracadabra Nov 28 '18 at 10:20

7 Answers7

45

the solution for this issue is.

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT < 16) {
                view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            } else {
                view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
            BottomSheetDialog dialog = (BottomSheetDialog) getDialog();
            FrameLayout bottomSheet = (FrameLayout)
            dialog.findViewById(android.support.design.R.id.design_bottom_sheet);
            BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
            behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            behavior.setPeekHeight(0); // Remove this line to hide a dark background if you manually hide the dialog.
        }
    });
}
CoolMind
  • 26,736
  • 15
  • 188
  • 224
avez raj
  • 2,055
  • 2
  • 22
  • 37
  • 4
    Don't forget to unregister the listener once the event is fired. – Eugen Pechanec Aug 16 '17 at 06:34
  • 3
    Thanks! I had issue with this: blackout is not dissapearing when dialog hides. Commenting out this line helped me: `behavior.setPeekHeight(0);` – Sam Sch Apr 17 '18 at 07:15
  • Hacky, but it works. This is risky because it depends on ```android.support.design.R.id.design_bottom_sheet``` which Google can decide to rename at any moment and would result in broken code. Are there any other ways to achieve this through native Android SDK methods? – Ivan Jun 12 '18 at 21:58
  • @Ivan Your code won't compile if they will rename it in support library. – Divers Jun 19 '18 at 12:26
  • 15
    If you're using `androidx` libraries you should use `com.google.android.material.R.id.design_bottom_sheet` – idish Nov 12 '18 at 17:11
  • I added an unregistration of the listener to the code. – CoolMind Apr 16 '19 at 15:07
  • A delay is needed to avoid strange behaviour on showing bottom sheet – Morteza Rastgoo May 15 '19 at 10:00
  • instead of `behavior?.peekHeight = 0` one should use `behavior?.skipCollapsed = true` – ildar ishalin Nov 12 '20 at 05:21
  • Check https://stackoverflow.com/a/58067230/3981822 if above solution doesn't work – Shvet Dec 21 '20 at 13:30
29

This worked for me and was the cleanest approach:

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val dialog = BottomSheetDialog(requireContext(), theme)
    dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
    return dialog
}
MakinTosH
  • 623
  • 7
  • 12
  • It will be more helpful if you also post some explanation, for example why you choose this approach. Please read https://stackoverflow.com/help/how-to-answer – 32cupo May 15 '20 at 07:04
  • 2
    In recent apis dialog.behavior is not exposed, it is private – Mohanakrrishna Jul 16 '20 at 04:59
  • It's public. Just checked it out: [dialog.behavior.state](https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior#setstate) – MakinTosH Jul 16 '20 at 05:12
  • 2
    You can also replace the 2nd line with `val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog`. – CoolMind Jul 20 '20 at 07:56
  • If you get collapsed state when trying to dismiss or hide the dialog add this also: `dialog.behavior.skipCollapsed = true` – MakinTosH Sep 17 '20 at 07:52
17

Thanks to @avez raj and Prevent dismissal of BottomSheetDialogFragment on touch outside I wrote in onCreateDialog().

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val dialog = super.onCreateDialog(savedInstanceState)

    dialog.setOnShowListener {
        val bottomSheet = dialog.findViewById<View>(
            com.google.android.material.R.id.design_bottom_sheet) as? FrameLayout
        val behavior = BottomSheetBehavior.from(bottomSheet)
        behavior.state = BottomSheetBehavior.STATE_EXPANDED
    }

    return dialog
}

Currently I use MakinTosH solution, it is shorter.

CoolMind
  • 26,736
  • 15
  • 188
  • 224
  • 2
    Why does it occur though? In which cases does it get to be this way ? Is there an official way to handle it? Maybe we are supposed to handle it when it's not expanded, in a different way? Or is it a bug? I've noticed a weird bug related to it on the Play Store too : https://issuetracker.google.com/issues/133809189 – android developer May 29 '19 at 11:11
  • 1
    @androiddeveloper, good question, I don't know. BSDF is very bugged view. Especially when it concerns to keyboard. Thanks for your research. – CoolMind May 29 '19 at 12:29
  • 1
    But even without a keyboard it was collapsed to a much smaller size – android developer May 30 '19 at 16:22
  • 2
    @androiddeveloper, I suppose, they in Google company make weird and buddy components every day. Programmers have to create workarounds for every bug. My ex-colleague also noticed troubles in BSDF in full screen with keyboard and even wants to rewrite with fragment instead of BSDF. – CoolMind May 31 '19 at 07:59
  • I see. Thank you. – android developer May 31 '19 at 08:13
  • 1
    @androiddeveloper, probably I will ask him about details, if he changes the code. – CoolMind May 31 '19 at 12:48
6

The ViewTreeObserver solution did not work for me, but I found a superior solution here and converted it to Kotlin. This one doesn't have the expensive computational waste which comes with a ViewTreeObserver and nicely bundles the functionality into the class.

class ExpandedBottomSheetDialog(context: Context) : BottomSheetDialog(context) {

    override fun show() {
        super.show()
        // androidx should use: com.google.android.material.R.id.design_bottom_sheet
        val view = findViewById<View>(R.id.design_bottom_sheet)
        view!!.post {
            val behavior = BottomSheetBehavior.from(view)
            behavior.setState(BottomSheetBehavior.STATE_EXPANDED)
        }
    }
}
clever_trevor
  • 1,530
  • 2
  • 22
  • 42
  • 5
    This solution is not suitable for BottomSheetDialog`Fragment` as it uses `findViewById` that is is not attached to any `view` (it is `null` in this phase). Also, if you override `show(manager: FragmentManager?, tag: String?)` (see https://stackoverflow.com/questions/15729138/on-showing-dialog-i-get-can-not-perform-this-action-after-onsaveinstancestate) and use `super.show(manager, tag)`, then you will probably catch an exception. – CoolMind Apr 16 '19 at 11:14
4

You can simply do the following:

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
}
artenson.art98
  • 1,543
  • 15
  • 15
2

This is a problem of gestureInsetBottomIgnored. For landscape this flag is false, but for portrait is true.

Georgiy Chebotarev
  • 1,676
  • 3
  • 14
  • 18
0

Any reason why after adding `onConfigurationChanged, it did not work(need to drag it again in landscape)

// support when screen rotate, resize etc.
override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    rvLayoutManager.spanCount = getSpanCount()
    rvLayoutManager.requestLayout()
}

private fun getSpanCount(): Int {
    val widthPx = resources.displayMetrics.widthPixels
    val profileWidth = activity!!.resources.getDimension(R.dimen.profile_width)
    return Math.floor((widthPx / profileWidth).toDouble()).toInt()
}
teaaa
  • 1
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31252988) – Abhishek Dutt Mar 15 '22 at 05:37