我有一个自定义的bittomsheetdialogfragment,我想在底部视图的顶部有圆角

这是我的自定义类,它膨胀了我想要从底部显示的布局

View mView;

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

我还有这个XML资源文件作为背景:

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

问题是,当我把这个资源文件设置为我的布局的根元素的背景,角仍然不是圆角。

我不能使用以下代码:

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

因为它覆盖了底部对话框的默认背景,底部视图上方不会有任何半透明的灰色。


当前回答

首先,你应该创建一个可绘制的XML文件,其中包含一个顶部圆角的形状,任何你想要的名称。 我将其命名为bottom rounded_top_shape.xml

<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"
    />

然后在style.xml中添加这个

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

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

然后在你的应用主题中添加如下所示的行

 <style name="MyAppTheme" parent="Theme.MaterialComponents.Light.Bridge">
    <!-- this line -->
    <item name="bottomSheetDialogTheme">@style/AppBottomSheetDialogTheme</item>
</style>

其他回答

如果您正在使用材质组件主题,您可以通过将背景颜色设置为透明,然后将布局的背景设置为四舍五入来覆盖BottomSheetDialog的默认行为。

    <style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="bottomSheetDialogTheme">@style/BottomSheetDialog</item>
    </style>

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

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

rounded_corner.xml:

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

</shape>

然后将形状应用到你的底部表格根布局的背景:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/rounded_corner">

    <!-- 
       other layout components
     -->

</LinearLayout>

注意,如果你在底部表单布局中使用Webview这样的组件,你可能无法实现预期的圆角,因为Webview有一个默认的白色背景。在这种情况下,你可以像这样简单地删除背景:

webView.setBackgroundColor(0);

我今天也检查了同样的事情,是的,你是对的,下面的代码

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

这适用于片段背景,所以相反,你应该从对话框窗口获得底部表视图,并改变背景,这里是代码

 @SuppressLint("RestrictedApi")
    @Override
    public void setupDialog(Dialog dialog, int style) {
        super.setupDialog(dialog, style);
        View rootView = getActivity().getLayoutInflater().inflate(R.layout.view_member_info,null,false);
        unbinder = ButterKnife.bind(this, rootView);
        adjustUIComponents();
        dialog.setContentView(rootView);
        FrameLayout bottomSheet = (FrameLayout) dialog.getWindow().findViewById(android.support.design.R.id.design_bottom_sheet);
        bottomSheet.setBackgroundResource(R.drawable.container_background);
    }

这里的底部是你想要改变的实际视图。

使用新的材质组件库,您可以使用样式中的shapeAppearanceOverlay属性自定义组件的形状(注意:它至少需要1.1.0版本)

只需使用BottomSheetDialogFragment覆盖onCreateView方法,然后为BottomSheet对话框定义自定义样式。

在你的应用主题的styles.xml中定义bottomSheetDialogTheme属性:

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

然后用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>


你可以在你的BottomSheetDialogFragment中获得相同的行为覆盖这个方法(而不是在你的应用主题中添加bottomSheetDialogTheme):

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

在这种情况下,你只在一个BottomSheetDialogFragment中使用这个themeOverlay,而不是在所有的应用程序中。


关于EXPANDED STATE的重要注意事项:

在展开状态下,BottomSheet有平角。你可以在github repo查看官方评论:

我们的设计团队坚持认为圆角表示可滚动内容,而平角表示没有额外的内容。因此,他们不希望我们用fitToContents添加这个更改。

这个行为是由BottomSheetBehavior提供的,不可能重写它。 然而,有一个解决办法->免责声明:它可以停止工作在下一个版本!!

你可以在BottomSheetDialogFragment中添加一个BottomSheetCallback:

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

简单的解决方案:

class TopRoundedCornersFragment : BottomSheetDialogFragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setStyle(STYLE_NORMAL, R.style.AppBottomSheetDialogTheme)
    }
}

在styles.xml

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

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

最后,创建一个顶部圆角可绘制资源(bottom_sheet_dialog_bg.xml)

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

    <solid android:color="@android:color/white" />
    <corners
        android:topLeftRadius="4dp"
        android:topRightRadius="4dp" />

</shape>

在你的BottomsheetDialogFragment类中添加这两个方法。

public void setDialogBorder(Dialog dialog) {
        FrameLayout bottomSheet = (FrameLayout) dialog.getWindow().findViewById(android.support.design.R.id.design_bottom_sheet);
        bottomSheet.setBackground(new ColorDrawable(Color.TRANSPARENT));
        setMargins(bottomSheet, 10, 0, 10, 20);
    }

    private void setMargins(View view, int left, int top, int right, int bottom) {
        if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
            ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
            p.setMargins(left, top, right, bottom);
            view.requestLayout();
        }
    }

现在调用你的BottomsheetDialogFragment类的setupDialog()方法中的setDialogBorder(dialog)方法。

现在在可绘制文件夹中创建一个形状文件。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="20dp" />

    <solid android:color="@color/white" />
    <stroke
        android:width="1dp"
        android:color="@color/transparent" />
</shape>

现在在xml文件中设置父视图组对话框视图的背景。

android:background="@drawable/round_border_white"

完成了! !