Round corner for BottomSheetDialogFragment

115,838

Solution 1

Create a custom drawable rounded_dialog.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@android:color/white"/>
    <corners android:topLeftRadius="16dp"
        android:topRightRadius="16dp"/>

</shape>

Then override bottomSheetDialogTheme on styles.xml using the drawable as background:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">       
    <item name="bottomSheetDialogTheme">@style/AppBottomSheetDialogTheme</item>
</style>

<style name="AppBottomSheetDialogTheme"
    parent="Theme.Design.Light.BottomSheetDialog">
    <item name="bottomSheetStyle">@style/AppModalStyle</item>
</style>

<style name="AppModalStyle"
    parent="Widget.Design.BottomSheet.Modal">
    <item name="android:background">@drawable/rounded_dialog</item>
</style>

This will change all the BottomSheetDialogs of your app.

Solution 2

With the new Material Component library you can customize the shape of your component using the shapeAppearanceOverlay attribute in your style (Note: it requires at least the version 1.1.0)

Just use the BottomSheetDialogFragment overriding the onCreateView method and then define your custom style for Bottom Sheet Dialogs.

Define the bottomSheetDialogTheme attribute in styles.xml in your app theme:

  <!-- Base application theme. -->
  <style name="AppTheme" parent="Theme.MaterialComponents.Light">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    ....
    <item name="bottomSheetDialogTheme">@style/CustomBottomSheetDialog</item>
  </style>

Then just define your favorite shape with shapeAppearanceOverlay

  <style name="CustomBottomSheetDialog" parent="@style/ThemeOverlay.MaterialComponents.BottomSheetDialog">
    <item name="bottomSheetStyle">@style/CustomBottomSheet</item>
  </style>

  <style name="CustomBottomSheet" parent="Widget.MaterialComponents.BottomSheet">
    <item name="shapeAppearanceOverlay">@style/CustomShapeAppearanceBottomSheetDialog</item>
  </style>

  <style name="CustomShapeAppearanceBottomSheetDialog" parent="">
    <item name="cornerFamily">rounded</item>
    <item name="cornerSizeTopRight">16dp</item>
    <item name="cornerSizeTopLeft">16dp</item>
    <item name="cornerSizeBottomRight">0dp</item>
    <item name="cornerSizeBottomLeft">0dp</item>
  </style>

enter image description here


You can obtain the same behavior overriding this method in your BottomSheetDialogFragment (instead of adding the bottomSheetDialogTheme in your app theme):

@Override public int getTheme() {
    return R.style.CustomBottomSheetDialog;
  }

In this case you are using this themeOverlay only in the single BottomSheetDialogFragment and not in all the app.


Important note about the EXPANDED STATE:

In the expanded state the BottomSheet has flat corners . You can check the official comment in github repo:

Our design team is strongly opinionated that rounded corners indicate scrollable content while flat corners indicate that there is no additional content. As such, they do no want us to add this change with fitToContents.

This behavior is provided by the BottomSheetBehavior and it is impossible to override it.
However there is a workaround -> DISCLAIMER: it can stop to work in the next releases !!

You can add a BottomSheetCallback in the BottomSheetDialogFragment:

  @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
    Dialog dialog = super.onCreateDialog(savedInstanceState);


    ((BottomSheetDialog)dialog).getBehavior().addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {

      @Override public void onStateChanged(@NonNull View bottomSheet, int newState) {
        if (newState == BottomSheetBehavior.STATE_EXPANDED) {
          //In the EXPANDED STATE apply a new MaterialShapeDrawable with rounded cornes
          MaterialShapeDrawable newMaterialShapeDrawable = createMaterialShapeDrawable(bottomSheet);
          ViewCompat.setBackground(bottomSheet, newMaterialShapeDrawable);
        }
      }

      @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) {

      }
    });

    return dialog;
  }

  @NotNull private MaterialShapeDrawable createMaterialShapeDrawable(@NonNull View bottomSheet) {
    ShapeAppearanceModel shapeAppearanceModel =

      //Create a ShapeAppearanceModel with the same shapeAppearanceOverlay used in the style
      ShapeAppearanceModel.builder(getContext(), 0, R.style.CustomShapeAppearanceBottomSheetDialog)
        .build();

      //Create a new MaterialShapeDrawable (you can't use the original MaterialShapeDrawable in the BottoSheet)
      MaterialShapeDrawable currentMaterialShapeDrawable = (MaterialShapeDrawable) bottomSheet.getBackground();
      MaterialShapeDrawable newMaterialShapeDrawable = new MaterialShapeDrawable((shapeAppearanceModel));
      //Copy the attributes in the new MaterialShapeDrawable
      newMaterialShapeDrawable.initializeElevationOverlay(getContext());
      newMaterialShapeDrawable.setFillColor(currentMaterialShapeDrawable.getFillColor());
      newMaterialShapeDrawable.setTintList(currentMaterialShapeDrawable.getTintList());
      newMaterialShapeDrawable.setElevation(currentMaterialShapeDrawable.getElevation());
      newMaterialShapeDrawable.setStrokeWidth(currentMaterialShapeDrawable.getStrokeWidth());
      newMaterialShapeDrawable.setStrokeColor(currentMaterialShapeDrawable.getStrokeColor());
      return newMaterialShapeDrawable;
  }

Solution 3

The BottomSheetDialog is setting a default white background color , this is why the corners are not visible, In order to show them you need to make the background of the dialog transparent by overriding the style of the BottomSheetDialog.

Define this style In your res/values/styles/styles.xml

<style name="BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
    <item name="bottomSheetStyle">@style/bottomSheetStyleWrapper</item>
</style>

<style name="bottomSheetStyleWrapper" parent="Widget.Design.BottomSheet.Modal">
    <item name="android:background">@android:color/transparent</item>
</style>

And set this style to your BottomSheetDialog

View view = getLayoutInflater().inflate(R.layout.chooser_bottom_sheet, null);
BottomSheetDialog dialog = new BottomSheetDialog(this,R.style.BottomSheetDialog); // Style here
dialog.setContentView(view);
dialog.show();

Solution 4

create a shape named rounded_corners_shape

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <corners
        android:topLeftRadius="8dp"
        android:topRightRadius="8dp"/>
    <solid android:color="@color/white"/>

</shape>

define a style

  <style name="AppBottomSheetDialogTheme"
           parent="Theme.Design.Light.BottomSheetDialog">
        <item name="bottomSheetStyle">@style/AppModalStyle</item>
    </style>

    <style name="AppModalStyle" parent="Widget.Design.BottomSheet.Modal">
        <item name="android:background">@drawable/rounded_corners_shape</item>
    </style>

use this style on your custom BottomSheetDialogFragment like this, it will be work!

 public class CustomDialogFragment extends BottomSheetDialogFragment {
      @Override
      public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(STYLE_NORMAL, R.style. AppBottomSheetDialogTheme);
      }

      ...
    }

Solution 5

This worked for me.

Create a background drawable (e.g. named shape_rounded_dialog):

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">

    <solid android:color="@color/color_white" />
    <corners android:topLeftRadius="16dp"
             android:topRightRadius="16dp" />
</shape>

Add the styles below:

<style name="AppBottomSheetDialogTheme" 
       parent="Theme.MaterialComponents.Light.BottomSheetDialog">

    <item name="bottomSheetStyle">@style/CustomBottomSheetStyle</item>
</style>

<style name="CustomBottomSheetStyle" 
       parent="Widget.Design.BottomSheet.Modal">

    <item name="android:background">@drawable/shape_rounded_dialog</item>
</style>

In your DialogFragment, override the method getTheme() to return your style.

@Override
public int getTheme() {
    return R.style.AppBottomSheetDialogTheme;
}
Share:
115,838

Related videos on Youtube

Russell Ghana
Author by

Russell Ghana

Updated on April 11, 2022

Comments

  • Russell Ghana
    Russell Ghana about 2 years

    I have a custom BttomSheetDialogFragment and I want to have round corners in top of Bottom View

    This is my Custom class that inflates my layout that I want to appear from bottom

    View mView;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mView = inflater.inflate(R.layout.charge_layout, container, false);
        initChargeLayoutViews();
        return mView;
    }
    

    and also I have this XML resource file as background:

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle"
        >
        <corners android:topRightRadius="35dp"
            android:topLeftRadius="35dp"
            />
        <solid android:color="@color/white"/>
    
        <padding android:top="10dp"
            android:bottom="10dp"
            android:right="16dp"
            android:left="16dp"/>
    </shape>
    

    The problem is, when I set this resource file as background of my Layout's root element, the corners still are not rounded.

    I can't use below code:

    this.getDialog().getWindow().setBackgroundDrawableResource(R.drawable.charge_layout_background);
    

    Because it overrides the default background of BottomSheetDialog and there won't be any semi-transparent gray color above my Bottom View.

  • jssingh
    jssingh about 6 years
    This should be the right solution because it works for all DialogFragments without jumping through hoops.
  • Nick Dev
    Nick Dev about 6 years
    For me, there are still white corners behind my rounded corners. So when I change the color of my drawable to red, your code works correctly and creates a rounded red rectangle, but behind that there is still a default white rectangle. The "dialog.getWindow().setBackgroundDrawable..." code you wrote changes the color of the entire "darkened" area above my dialog, but again, it misses those two little corners. Do you know what could be causing this issue?
  • Nick Dev
    Nick Dev about 6 years
    Adding on to my comment above, I should note that I had to change the code in onCreateView() to "getDialog().getWindow()..." in order for my code to run. Perhaps this is why it doesn't work for me.
  • Variag
    Variag about 6 years
    @NickDev Post new question if you think this solution does not apply to your code and maybe we'll find a solution.
  • Nick Dev
    Nick Dev about 6 years
    @Variag Thanks for reaching out; I actually came up with a cheap workaround where I cover the default bottom sheet modal dialog with a rectangle that is the same color as the darkened area behind it. Then I added a second rectangle with rounded corners on top of that. It's not ideal, but it looks great! I appreciate the help nonetheless.
  • Ivan Shafran
    Ivan Shafran almost 6 years
    It works for me. Also I noticed it depends on layout root element. Firstly I had cardview as root (cause I tried another way to round corners), then I changed it to linear layout and now it works perfectly
  • tmm1
    tmm1 almost 6 years
    Which view do you use with setMargins?
  • DalveerSinghDaiya
    DalveerSinghDaiya almost 6 years
    FrameLayout bottomSheet ; This one defined in setDialogBorder() method. This actually is the default view for the bottom sheet dialog in android. It will work fine.
  • Morteza Rastgoo
    Morteza Rastgoo about 5 years
    Crashes on android api 17
  • UditS
    UditS almost 5 years
    It would be helpful if you add some clarification along with the code.
  • DYS
    DYS almost 5 years
    This is the right place to set theme for Fragments.
  • Gabriele Mariotti
    Gabriele Mariotti over 4 years
    @Tadhg Use 1.1.0-beta01
  • Tadhg
    Tadhg over 4 years
    Oh whoops, I’m on 1.2.0alpha02 in order to support the new wonky “spinners”. I was able to get this code working on 1.2.0.02 but it doesn’t utilise the new shape component stuff.
  • Gabriele Mariotti
    Gabriele Mariotti over 4 years
    @androidguy thanks for feedback. I have to check it but it seems a bug of the library. In any case I don't work in the material components team.
  • androidguy
    androidguy over 4 years
    I have reported this issue: issuetracker.google.com/issues/144859239 If anyone has any further findings or solution for the issue, please reply. Thanks!
  • Kirill Starostin
    Kirill Starostin over 4 years
    The only way i got this working. Btw i'm using BottomSheetDialogFragment so that logic is in the onCreateDialog method
  • hmac
    hmac over 4 years
    I wouldn't use rounded_dialog & AppModalStyle names with a background where only the top corners are rounded, as you would only expect to use such a background with a bottom sheet style. How about bottomsheet_rounded_background & AppBottomSheetStyle
  • hmac
    hmac over 4 years
    Note if you specify a background on the root view then this will override this setting
  • hkchakladar
    hkchakladar over 4 years
    I'm getting this error and crash on v1.1.0-beta02 Could not inflate Behavior subclass com.google.android.material.bottomsheet.BottomSheetBehavior
  • José Carlos
    José Carlos over 4 years
    It doesn't work if bottom sheet dialog is expanded. Any idea?
  • José Carlos
    José Carlos over 4 years
    In my case, I have had to override shapeAppearance. <style name="CustomBottomSheet" parent="Widget.MaterialComponents.BottomSheet"> <item name="shapeAppearance">@style/CustomShapeAppearanceBottomShe‌​etDialog</item> <item name="shapeAppearanceOverlay">@style/CustomShapeAppearanceBo‌​ttomSheetDialog</ite‌​m> </style>
  • Luke Needham
    Luke Needham about 4 years
    Better than the accepted answer, because this way you can have different backgrounds on different BottomSheetDialogs
  • Code Wiget
    Code Wiget about 4 years
    Can this be done without using a theme? When I use Theme.AppCompat.Light.NoActionBar it causes all of my UI components to change colors and I can't override them
  • Emil Mammadov
    Emil Mammadov about 4 years
    Thanks. Works great!
  • Arnold Brown
    Arnold Brown almost 4 years
    Now curve visible, but a transparent color throughout the screen on touch only the white color on bottom dialog is visible @Badr any corrrection?
  • Gabriele Mariotti
    Gabriele Mariotti almost 4 years
    @JoséCarlos In the expanded state it doesn't work because it is a default behavior. (github.com/material-components/material-components-android/‌​pull/…). I updated the answer with a workaround if you want to override the default.
  • MFQ
    MFQ almost 4 years
    Thank you bro, it works and I love you forever dear stranger
  • d-feverx
    d-feverx almost 4 years
    As compared to other it is a much better solution, because most of the solution out there is base on set custom drawable
  • Neon Warge
    Neon Warge almost 4 years
    This is neat, but it doesn't seem to work on my end.
  • Alex_297
    Alex_297 almost 4 years
    Have found a way to have rounded corners even in expanded state with 1.1.0 version. Just added transparent backgroundTint. <style name="CustomBottomSheetDialog" parent="@style/ThemeOverlay.MaterialComponents.BottomSheetDi‌​alog"> <item name="bottomSheetStyle">@style/CustomBottomSheet</item> <item name="android:backgroundTint">@color/transparent</item> </style>
  • Vikas Acharya
    Vikas Acharya almost 4 years
    This was the perfect and latest answer. I need to mark this as answer
  • Jaden Gu
    Jaden Gu almost 4 years
    Looks nice. Does this also apply to BottomSheetDialog ?
  • Sourabh
    Sourabh over 3 years
    This had not worked for me. After a invalidating cache and restarting android studio it worked all of a sudden.
  • MMK
    MMK over 3 years
    make sure you don’t have any background on root element of your sheet layout!
  • nitinkumarp
    nitinkumarp over 3 years
    Note to all: Using this answer will cause all component using ShapeAppearance.MaterialComponents.LargeComponent to have same cornerSize and family, not just Bottom Sheet. Check your style requirement and decide if you want change appearance for all component or just individual component or widget.
  • Prateek Gupta
    Prateek Gupta over 3 years
    That's the solution I was looking for, Totally hack free.
  • DIRTY DAVE
    DIRTY DAVE over 3 years
    So many steps just to add rounded corners....Thanks for posting this though.
  • necavit
    necavit over 3 years
    I must "inject" the theme by overriding getTheme(), because our app theme does not yet inherit from any Material theme. However, I am also facing an exception "Could not inflate Behavior subclass com.google.android.material.bottomsheet.BottomSheetBehavior"‌​, like @hkchakladar commented. Has anyone else faced this issue and got it solved? It feels like some theming attributes are missing, but since we're using a Theme.Overlay... I find that weird. Still struggling with it after setting a bunch of Material theme attributes on the overlay.
  • Sandy
    Sandy over 3 years
    Solution with simple understandable explanation kudos @Badr
  • jaumebd
    jaumebd about 3 years
    Thanks! You saved my day explaining the change needed from Theme.AppCompat... to Theme.MaterialComponents... It was driving me crazy
  • mafortis
    mafortis about 3 years
    It also needs background transparent on onViewCreated which clears out background under radiused corners and you can actually see the corners (view?.parent as View).setBackgroundColor(Color.TRANSPARENT)
  • Vikas Patidar
    Vikas Patidar about 3 years
    If you are using a toolbar on the top in BottomSheetDialogFragment then rounded corners won't show up.
  • Randunu.KSW
    Randunu.KSW about 3 years
    this solution is also working with com.google.android.material:material:1.3.0
  • Burak
    Burak over 2 years
    This worked for me, thanks!
  • Naimul Kabir
    Naimul Kabir over 2 years
    Thanks a lot, man. This is the latest solution as of 26 September 2021.
  • Kenny
    Kenny over 2 years
    Doesn't seem to work anymore in 1.4 :/
  • Kenny
    Kenny over 2 years
    This worked to get the dialog shape as you'd like, but it loses all the other setup attributes from the theme as well. Just FYI
  • Rick Robin
    Rick Robin over 2 years
    Simple and effective
  • Maher Abuthraa
    Maher Abuthraa over 2 years
    Elegant solution👍🏼
  • c-an
    c-an over 2 years
    this loses dialog's behaviour
  • Zain
    Zain over 2 years
    @c-an Thanks for this; I just enhanced the answer with a different approach; hopefully it helps
  • Najib.Nj
    Najib.Nj over 2 years
    Perfect answer working like charm !! :)
  • Tuan Dao
    Tuan Dao over 2 years
    this isn't work if you expand bottom sheet
  • Ankit Gupta
    Ankit Gupta over 2 years
    Not working as of Feb 2021
  • Vishnu
    Vishnu about 2 years
    The only one that worked for me. Thanks Badr.