【问题标题】:Round corner for BottomSheetDialogFragmentBottomSheetDialogFragment 的圆角
【发布时间】:2017-10-06 17:54:34
【问题描述】:

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

这是我的自定义类,它扩展了我想从底部显示的布局

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

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

【问题讨论】:

标签: android material-design bottom-sheet material-components-android material-components


【解决方案1】:

我今天检查了同样的事情,是的,您对以下代码的看法是正确的

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

here bottomsheet 是您要更改的实际视图。

【讨论】:

  • 我得到这个工作的唯一方法。顺便说一句,我正在使用BottomSheetDialogFragment,因此逻辑在onCreateDialog 方法中
【解决方案2】:

解决此问题的另一种方法是扩展 BottomSheetDialog 并创建一个适合您需求的自定义类。您可以对布局 xml 文件执行相同的操作,并添加背景或任何其他所需的自定义。这还有一个好处,即您在更改背景时将不依赖于 Android (android.support.design.R.id.design_bottom_sheet) 使用的 id 名称(尽管 id 名称的更改很少发生 AFAIK)。

【讨论】:

    【解决方案3】:

    Koma Yipanother question 的回答对我有用,你应该试试。

    在 drawable 中创建一个 xml,比如 dialog_bg.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="@color/white"/>
        <corners android:radius="30dp" />
        <padding
            android:left="10dp"
            android:top="10dp"
            android:right="10dp"
            android:bottom="10dp" />
    </shape>
    

    把它放在你的布局xml根节点中:

    将其设置为布局 xml 中的背景

    android:background="@drawable/dialog_bg"
    

    并在onCreateView() 中输入:

    将对话框的背景设置为透明

    dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
    

    【讨论】:

    • 这应该是正确的解决方案,因为它适用于所有 DialogFragment 而无需跳过任何环节。
    • 对我来说,圆角后面还有白角。 因此,当我将可绘制对象的颜色更改为红色时,您的代码可以正常工作并创建一个圆角红色矩形,但在这之后仍然有一个默认的白色矩形。您编写的 "dialog.getWindow().setBackgroundDrawable..." 代码更改了我的对话框上方整个“变暗”区域的颜色,但同样,它错过了这两个小角落。 您知道导致此问题的原因吗?
    • 补充我上面的评论,我应该注意到我必须将 onCreateView() 中的代码更改为 "getDialog().getWindow()..." 以便我的代码运行。也许这就是为什么它对我不起作用。
    • @NickDev 如果您认为此解决方案不适用于您的代码,请发布新问题,也许我们会找到解决方案。
    • @Variag 感谢您与我们联系;实际上,我想出了一个便宜的解决方法,我用一个与它后面的深色区域相同颜色的矩形覆盖默认的底部表单模式对话框。然后我在上面添加了第二个带圆角的矩形。这并不理想,但看起来很棒!尽管如此,我还是感谢您的帮助。
    【解决方案4】:

    在您的 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"
    

    完成!!

    【讨论】:

    • setMargins 使用哪种视图?
    • FrameLayout bottomSheet ;这在 setDialogBorder() 方法中定义。这实际上是 android 中底部工作表对话框的默认视图。它会正常工作的。
    【解决方案5】:

    创建一个带有圆角的自定义drawable并将其设置为您的BottomSheetDialogFragment布局根的背景

    <?xml version="1.0" encoding="UTF-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    
    <solid android:color="@color/colorPrimary" />
    
    <corners
        android:bottomLeftRadius="0dp"
        android:bottomRightRadius="0dp"
        android:topLeftRadius="12dp"
        android:topRightRadius="12dp" />
    
    </shape>
    

    然后只需将以下代码添加到您的 BottomSheetDialogFragment 类中

    @Override
    public void setupDialog(Dialog dialog, int style) {
        super.setupDialog(dialog, style);
        View contentView = View.inflate(getContext(), 
    R.layout.fragment_bottom_sheet, null);
        dialog.setContentView(contentView);
    
        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent())
                .getLayoutParams();
        CoordinatorLayout.Behavior behavior = params.getBehavior();
        ((View) contentView.getParent()).setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
    }
    

    您甚至可以使用参数来设置如下边距

    params.setMargins(50, 0, 50, 0);
    

    【讨论】:

      【解决方案6】:

      BottomSheetDialog 设置了默认的白色背景颜色,这就是为什么角落不可见的原因,为了显示它们,您需要通过覆盖 BottomSheetDialog 的样式使对话框的背景透明。

      在你的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>
      

      并将此样式设置为您的 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();
      

      【讨论】:

      • 比公认的答案更好,因为这样你可以在不同的 BottomSheetDialogs 上拥有不同的背景
      • 现在曲线可见,但触摸时整个屏幕的透明颜色只有底部对话框上的白色可见@Badr 有什么更正吗?
      • 这就是我正在寻找的解决方案,完全免费。
      • 解决方案,简单易懂的解释赞@Badr
      • 优雅的解决方案??
      【解决方案7】:

      此答案仅针对在为布局设置圆形背景的可绘制对象后将背景颜色设置为Color.TRANSPARENT 的问题。

      除了覆盖setupDialog() 解决方案之外,没有一个答案对我有用,将背景颜色设置为Color.TRANSPARENT

      @Override
      public void setupDialog(Dialog dialog, int style) {
          super.setupDialog(dialog, style);
          View contentView = View.inflate(getContext(), 
      R.layout.fragment_bottom_sheet, null);
          dialog.setContentView(contentView);
          ...
          ((View) contentView.getParent()).setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
      }
      

      但是您在此处为对话框设置的contentView 不是您在onCreateView() 中膨胀时在onViewCreated() 中获得的view。它破坏了标准流程,因此可能会出现无法在onViewCreated() 中使用View Bindings - Kotlin Android Extensions 等问题

      所以我稍微调整一下以在onActivityCreated() 中设置背景:

      override fun onActivityCreated(savedInstanceState: Bundle?) {
          super.onActivityCreated(savedInstanceState)
          (view?.parent as View).setBackgroundColor(Color.TRANSPARENT)
        }
      

      希望对遇到同样问题的人有所帮助

      【讨论】:

        【解决方案8】:

        创建自定义可绘制对象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>
        

        然后使用drawable作为背景覆盖styles.xml上的bottomSheetDialogTheme

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

        这将更改您应用的所有 BottomSheetDialogs。

        【讨论】:

        • 它对我有用。我还注意到它取决于布局根元素。首先我将cardview作为root(因为我尝试了另一种圆角的方法),然后我将其更改为线性布局,现在它可以完美运行
        • android api 17 崩溃
        • 请注意,如果您在根视图上指定背景,那么这将覆盖此设置
        • 确保您的工作表布局的根元素没有任何背景!
        • 这么多步骤只是为了添加圆角....感谢您发布此内容。
        【解决方案9】:
        1. 创建一个可绘制的形状 .. 我们将用作底页的背景。 为左上角和右上角的半径提供适当的值。

          <?xml version="1.0" encoding="utf-8"?>
          <shape xmlns:android="http://schemas.android.com/apk/res/android"
              android:shape="rectangle">
              <corners
                  android:topLeftRadius="24dp"
                  android:topRightRadius="24dp" />
              <padding android:top="2dp" />
              <solid android:color="@color/white" />
          </shape>
          
        2. 现在为“底部工作表对话框片段”创建样式

          <style name="BottomSheet" parent="@style/Widget.Design.BottomSheet.Modal">
                  <item name="android:background">@drawable/drawable_bottomsheet_background</item>
              </style>
          
              <style name="BaseBottomSheetDialog" parent="@style/Theme.Design.Light.BottomSheetDialog">
                  <item name="android:windowIsFloating">false</item>
                  <item name="bottomSheetStyle">@style/BottomSheet</item>
              </style>
          
              <style name="BottomSheetDialogTheme" parent="BaseBottomSheetDialog" />
          
        3. 现在创建一个自定义类,该类将扩展 BottomSheetDilogFragment,您可以在其中提供您的样式。

          open class CustomRoundBottomSheet : BottomSheetDialogFragment() {
          
              override fun getTheme(): Int = R.style.BottomSheetDialogTheme
          
              override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = BottomSheetDialog(requireContext(), theme)
          
          }
          
        4. 现在在任何你想有圆角底片的地方使用这个类。 例如

          class BottomSheetSuccess : CustomRoundBottomSheet() {
          
              override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
                  return inflater.inflate(R.layout.bottomsheet_shopcreate_success, container, false)
              }
          
          
              override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
                  super.onViewCreated(view, savedInstanceState)
              }
          
          } 
          

        【讨论】:

          【解决方案10】:

          你必须更改bottom sheet theme才能实现顶轮布局

          创建自定义可绘制背景_bottom_sheet_dialog_fragment.xml:

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

          然后使用drawable作为背景覆盖styles.xml上的bottomSheetDialogTheme:

          <!--Bottom sheet-->
          <style name="BottomSheet" parent="@style/Widget.Design.BottomSheet.Modal">
              <item 
              name="android:background">@drawable/background_bottom_sheet_dialog_fragment
              </item>
          </style>
          
          <style name="BaseBottomSheetDialog" 
              parent="@style/Theme.Design.Light.BottomSheetDialog">
              <item name="android:windowIsFloating">false</item>
              <item name="bottomSheetStyle">@style/BottomSheet</item>
          </style>
          
          <style name="BottomSheetDialogTheme" parent="BaseBottomSheetDialog" />
          

          这将改变底部工作表的背景布局

          BottomSheetDialog

          class SheetFragment() : BottomSheetDialogFragment() {
          
              lateinit var binding: SheetFragmentBinding;
          
            override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
              val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog;
              val view = View.inflate(context, R.layout.fragment_bottom_sheet, null);
          
              binding = DataBindingUtil.bind(view)!!;
              binding.viewModel = SheetFragmentVM();
          
              dialog.setContentView(view);
          
              var bottomSheetBehavior = BottomSheetBehavior.from(view.parent as View);
              bottomSheetBehavior.setPeekHeight(BottomSheetBehavior.PEEK_HEIGHT_AUTO);
          
              bottomSheetBehavior.setBottomSheetCallback(object : 
               BottomSheetBehavior.BottomSheetCallback() {
                  override fun onStateChanged(bottomSheet: View, newState: Int) {
                      if (BottomSheetBehavior.STATE_EXPANDED == newState) {
                         // do on STATE_EXPANDED
                      }
                      if (BottomSheetBehavior.STATE_COLLAPSED == newState) {
                          // do on STATE_COLLAPSED
                      }
          
                      if (BottomSheetBehavior.STATE_HIDDEN == newState) {
                          dismiss()
          
                      }
                  }
          
                  override fun onSlide(bottomSheet: View, slideOffset: Float) {
                     // do on slide
                  }
              })
          
              return dialog
          }
          

          【讨论】:

            【解决方案11】:

            创建一个名为 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>
            

            定义样式

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

            像这样在您的自定义 BottomSheetDialogFragment 上使用这种样式,它会起作用!

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

            【讨论】:

            • 如果您在代码中添加一些说明会很有帮助。
            • 这是为Fragments 设置主题的正确位置。
            • 这对我有用,谢谢!
            【解决方案12】:

            使用新的 Material Component 库,您可以在您的样式中使用 shapeAppearanceOverlay 属性 customize the shape 组件(注意:它至少需要版本1.1.0)

            只需使用 BottomSheetDialogFragment 覆盖 onCreateView 方法,然后为底部工作表对话框定义您的自定义样式。

            在您的应用主题的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,而不是在所有应用中。


            关于扩展状态的重要说明

            在展开状态下,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;
              }
            

            【讨论】:

            • 我已报告此问题:issuetracker.google.com/issues/144859239 如果有人对此问题有任何进一步的发现或解决方案,请回复。谢谢!
            • 我收到此错误并在 v1.1.0-beta02 Could not inflate Behavior subclass com.google.android.material.bottomsheet.BottomSheetBehavior 上崩溃
            • 如果底部工作表对话框展开,它不起作用。有什么想法吗?
            • 这很简洁,但对我来说似乎不起作用。
            • 这是完美的最新答案。我需要将此标记为答案
            【解决方案13】:

            如果您使用last version of material component,您只需覆盖ShapeAppearance.MaterialComponents.LargeComponent(因为底部工作表使用此形状)并设置您想要的值:

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

            然后设置你的应用风格:

            <item name="shapeAppearanceLargeComponent">@style/ShapeAppearance.YourApp.LargeComponent</item>
            

            The solution of Gabriele Mariotti 类似,也可以工作,但这个更简单。

            【讨论】:

            • 与其他解决方案相比,它是一个更好的解决方案,因为大多数解决方案都是基于设置自定义可绘制对象
            • 看起来不错。这也适用于BottomSheetDialog 吗?
            • 请注意:使用此答案将导致所有使用 ShapeAppearance.MaterialComponents.LargeComponent 的组件具有相同的cornerSize 和系列,而不仅仅是底部表。检查您的样式要求并决定是要更改所有组件的外观还是仅更改单个组件或小部件的外观。
            【解决方案14】:

            我知道这个问题已经有一个公认的答案。我想记录下我遇到的问题以及我最终是如何让它工作的,以便对未来的人有用。

            首先,我使用Theme.AppCompat.Light.DarkActionBar 作为AppTheme 的父级。这意味着@Gabriele Mariotti 解决方案不断因错误Could not inflate Behavior subclass com.google.android.material.bottomsheet.BottomSheetBehavior 而崩溃。我通过简单地将父级更改为Theme.MaterialComponents.Light.DarkActionBar 来解决此问题。这并没有以任何方式影响我们的主题,但 RTE 已经消失了。您也可以通过简单地将所需项目包含到您的样式中来解决此问题。但我没有费心去弄清楚 BottomSheetBehavior 需要哪些样式。

            其次,尽我所能尝试,但我无法获得具有圆角的实际框架布局(即 BottomSheetDialogFragment)。我意识到将其设置为可绘制的图像有效,但不适用于形状或@null。原来,这是因为我使用的LinearLayout 定义了背景。这覆盖了风格中的任何背景。删除最终导致圆角。

            另外,我不需要将任何背景形状设置为圆角。 @Gabriele Mariotti 的解决方案在我进行上述更改后立即起作用。但是,要设置我想要的背景颜色,我必须覆盖“backgroundTint”项。

            PS:我是 Android 开发新手,我正在维护一个旧应用程序,该应用程序是为我们学院内部使用而制作的。我对 Android 的布局系统或材质库不是很熟悉。我想这就是为什么我花了 3 天时间才弄清楚这一点的原因。我希望这对将来的某人有用。

            【讨论】:

            • 谢谢!您节省了我解释从 Theme.AppCompat... 到 Theme.MaterialComponents... 所需的更改的时间,这让我发疯了
            【解决方案15】:

            这对我有用。

            创建一个背景可绘制对象(例如,命名为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>
            

            添加以下样式:

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

            在您的 DialogFragment 中,覆盖方法 getTheme() 以返回您的样式。

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

            【讨论】:

            • 简单有效
            • 如果您展开底部表格,这将不起作用
            【解决方案16】:

            添加圆角形状,使其成为根布局的背景

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

            在您的 BottomSheetDialogFragment 上使背景透明

            override fun onActivityCreated(savedInstanceState: Bundle?) {
                super.onActivityCreated(savedInstanceState)
                (view?.parent as View).setBackgroundColor(Color.TRANSPARENT)
            }
            

            它适用于 Contraintlayout、Framelyaout、Linearlayout、Relativelayout。

            【讨论】:

              【解决方案17】:

              完整的解决方案:

              将以下样式属性添加到 style.xml。

              <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/bottom_sheet_background</item>
              </style>
              

              然后使用 AppBottomSheetDialogTheme 从您的代码中创建底部工作表对话框。

              private fun openBottomSheetTermsCondition() {
                  val mBottomSheetDialog = BottomSheetDialog(requireContext(),R.style.AppBottomSheetDialogTheme)
                  val sheetView = layoutInflater.inflate(R.layout.bottom_sheet_travel_advice_terms, null)
                  mBottomSheetDialog.setContentView(sheetView)
                  sheetView.tv_head.setOnClickListener {
                      mBottomSheetDialog.dismiss()
                  }
              
                  sheetView.webView.loadDataWithBaseURL(null,getString(R.string.privacy_policy_body_html),"text/html", "utf-8", null)
                  mBottomSheetDialog.show()
              }
              

              我使用下面的 drawable 来圆底部工作表背景。

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

              底页 xml bottom_sheet_travel_advice_terms.xml

                  <?xml version="1.0" encoding="utf-8"?>
              <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:app="http://schemas.android.com/apk/res-auto"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  app:behavior_hideable="false"
                  app:behavior_peekHeight="@dimen/bottom_sheet_peek_height"
                  app:cardCornerRadius="@dimen/spacing_normal"
                  app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
              
                  <androidx.constraintlayout.widget.ConstraintLayout
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:paddingBottom="@dimen/spacing_small">
              
                      <androidx.constraintlayout.widget.Guideline
                          android:id="@+id/begin_horizontal_guideline"
                          android:layout_width="wrap_content"
                          android:layout_height="wrap_content"
                          android:orientation="horizontal"
                          app:layout_constraintGuide_begin="@dimen/activity_vertical_margin" />
              
                      <androidx.constraintlayout.widget.Guideline
                          android:id="@+id/begin_vertical_guideline"
                          android:layout_width="wrap_content"
                          android:layout_height="wrap_content"
                          android:orientation="vertical"
                          app:layout_constraintGuide_begin="@dimen/activity_horizontal_margin" />
              
                      <androidx.constraintlayout.widget.Guideline
                          android:id="@+id/end_vertical_guideline"
                          android:layout_width="wrap_content"
                          android:layout_height="wrap_content"
                          android:orientation="vertical"
                          app:layout_constraintGuide_end="@dimen/activity_horizontal_margin" />
              
                      <View
                          android:id="@+id/sheet_header_shadow"
                          android:layout_width="match_parent"
                          android:layout_height="@dimen/spacing_tiny"
                          android:layout_marginStart="10dp"
                          android:layout_marginEnd="10dp"
                          android:background="@drawable/bottom_sheet_header_shadow"
                          app:layout_constraintEnd_toEndOf="parent"
                          app:layout_constraintStart_toStartOf="parent"
                          app:layout_constraintTop_toTopOf="parent" />
              
                      <androidx.appcompat.widget.AppCompatTextView
                          android:id="@+id/tv_head"
                          android:layout_width="0dp"
                          android:layout_height="wrap_content"
                          android:drawablePadding="@dimen/spacing_normal"
                          android:fontFamily="sans-serif-medium"
                          android:gravity="start"
                          android:padding="@dimen/spacing_small"
                          android:text="@string/term_and_condition"
                          android:textColor="@color/greyish_brown"
                          android:textSize="20sp"
                          app:drawableLeftCompat="@drawable/ic_close_black_24dp"
                          app:layout_constraintEnd_toEndOf="@id/end_vertical_guideline"
                          app:layout_constraintStart_toStartOf="@id/begin_vertical_guideline"
                          app:layout_constraintTop_toBottomOf="@+id/begin_horizontal_guideline" />
              
                      <View
                          android:id="@+id/line_separation"
                          android:layout_width="match_parent"
                          android:layout_height="1dp"
                          android:layout_marginTop="@dimen/spacing_small"
                          android:background="@color/blue_gray"
                          app:layout_constraintTop_toBottomOf="@+id/tv_head" />
              
                      <WebView
                          android:id="@+id/webView"
                          android:layout_width="0dp"
                          android:layout_height="wrap_content"
                          app:layout_constraintEnd_toEndOf="@id/end_vertical_guideline"
                          app:layout_constraintStart_toStartOf="@id/begin_vertical_guideline"
                          app:layout_constraintTop_toBottomOf="@id/line_separation" />
              
                  </androidx.constraintlayout.widget.ConstraintLayout>
              
              </androidx.cardview.widget.CardView>
              

              【讨论】:

                【解决方案18】:

                简单的解决方案:

                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>
                

                【讨论】:

                • 它还需要在onViewCreated 上透明背景,以清除圆角下的背景,您实际上可以看到角落(view?.parent as View).setBackgroundColor(Color.TRANSPARENT)
                【解决方案19】:

                setupDialog() 是 RestrictedApi。从material:1.3.0-beta01 开始工作的最简单的解决方案,无需触及主题:

                res/drawable/bs_background:

                <?xml version="1.0" encoding="utf-8"?>
                <shape xmlns:android="http://schemas.android.com/apk/res/android"
                  android:shape="rectangle">
                  <corners
                    android:topLeftRadius="16dp"
                    android:topRightRadius="16dp" />
                  <solid android:color="@color/dayNightBackground" />
                </shape>
                
                public class MyBsDialogFrag extends BottomSheetDialogFragment {
                
                @Override
                  public void onViewCreated(View view, Bundle savedInstanceState) {
                    super.onViewCreated(view, savedInstanceState);
                    ((View) view.getParent()).setBackgroundResource(R.drawable.bs_background);
                  }
                
                }
                

                【讨论】:

                • 在 1.4 中似乎不再工作:/
                【解决方案20】:

                具有弯曲形状和窥视高度的底页对话框

                    <!-- BottomSheet Dialog -->
                <style name="BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
                    <item name="bottomSheetStyle">@style/CustomBottomSheet</item>
                
                </style>
                
                
                <style name="CustomBottomSheet" parent="Widget.MaterialComponents.BottomSheet">
                    <item name="shapeAppearanceOverlay">@style/CustomShapeAppearanceBottomSheetDialog</item>
                    <item name="behavior_peekHeight">420dp</item>
                </style>
                
                <style name="CustomShapeAppearanceBottomSheetDialog" parent="">
                    <item name="cornerFamily">rounded</item>
                    <item name="cornerSizeTopRight">20dp</item>
                    <item name="cornerSizeTopLeft">20dp</item>
                    <item name="cornerSizeBottomRight">0dp</item>
                    <item name="cornerSizeBottomLeft">0dp</item>
                
                </style>
                

                【讨论】:

                  【解决方案21】:

                  如果您需要setFitContents=true,我尝试了通过挂钩onStateChanged 的解决方案,但是一旦对话框达到EXPANDED 状态,它就会从直角闪烁到圆角。很烦人。

                  有一种替代解决方法不会导致闪烁,不需要使用私有 API,并且更具可读性(恕我直言)。

                  查看BottomSheetBehavior的代码我们发现:

                    /** True if Behavior has a non-null value for the @shapeAppearance attribute */
                    private boolean shapeThemingEnabled;
                  

                  如果形状主题被禁用,MaterialShapeDrawable 将不会被使用。我们在BottomSheetBehavior.onLayout() 中找到了这个:

                  // Only set MaterialShapeDrawable as background if shapeTheming is enabled, otherwise will
                  // default to android:background declared in styles or layout.
                  if (shapeThemingEnabled && materialShapeDrawable != null) {
                    ViewCompat.setBackground(child, materialShapeDrawable);
                  }
                  

                  默认为android:background 正是我们所需要的,因为这意味着可以完全控制背景的渲染方式。

                  我们可以通过创建单独的样式并将 shapeAppearanceshapeAppearanceOverlay 设置为 null 来禁用材质主题:

                  <style name="Theme.YourApp.NoShapeBottomSheetDialog" parent="Theme.MaterialComponents.BottomSheetDialog">
                    <item name="bottomSheetStyle">@style/Theme.YourApp.NoShapeButtonSheet</item>
                  </style>
                  
                  <style name="Theme.YourApp.NoShapeButtonSheet" parent="Widget.MaterialComponents.BottomSheet.Modal">
                    <item name="shapeAppearance">@null</item>
                    <item name="shapeAppearanceOverlay">@null</item>
                  </style>
                  

                  扩展BottomSheetDialogFragment 并覆盖onCreateDialog

                  public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
                    return new BottomSheetDialog(requireContext(),
                                  R.style.Theme_Grupin_NoShapeBottomSheetDialog);
                  }
                  

                  底部的纸张现在是裸露的,根本没有任何背景。所以我们可以添加任何我们想要的背景,不会再触发动画了。

                  【讨论】:

                  • 这可以根据您的需要获得对话框形状,但它也会丢失主题中的所有其他设置属性。仅供参考
                  【解决方案22】:

                  第 1 步:

                  创建一个名为rounded_background.xmlres/drawable

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

                  第 2 步:

                  创建此样式以移除对话框背景:

                  <style name="NoBackgroundDialogTheme" parent="Theme.AppCompat.Light.Dialog">
                      <item name="android:windowBackground">@null</item>
                  </style>
                  

                  第 3 步:

                  使用setBackgroundResource() 将drawable 设置为对话框的根视图并通过覆盖getTheme() 方法设置样式

                  Java:

                  public class MyDialogFragment extends BottomSheetDialogFragment {
                  
                      @Override
                      public int getTheme() {
                          return R.style.NoBackgroundDialogTheme;
                      }
                  
                      @Nullable
                      @Override
                      public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                  
                          View view = View.inflate(requireContext(), R.layout.bottom_sheet_profile, null);
                          view.setBackgroundResource(R.drawable.rounded_background);
                          return view;
                  
                      }
                  }
                  

                  科特林:

                  class MyDialogFragment : BottomSheetDialogFragment() {
                  
                      override fun getTheme() = R.style.NoBackgroundDialogTheme
                  
                      override fun onCreateView(
                          inflater: LayoutInflater,
                          container: ViewGroup?,
                          savedInstanceState: Bundle?
                      ): View {
                  
                          val view: View = View.inflate(requireContext(), R.layout.bottom_sheet_profile, null)
                          view.setBackgroundResource(R.drawable.rounded_background)
                          return view
                      }
                  
                  }
                  

                  结果:

                  【讨论】:

                  • 这会丢失对话框的行为
                  • @c-an 谢谢你;我只是用不同的方法增强了答案;希望它有所帮助
                  【解决方案23】:

                  正如其他答案中所指出的,当状态为 BottomSheetBehavior.STATE_EXPANDED 时,角落将被展平。

                  您可以通过设置BottomSheetBehaviorpeekHeight 属性并使用您的自定义样式来解决此问题。

                  abstract class BaseBottomSheetFragment : BottomSheetDialogFragment(){
                  
                      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
                      
                          if (state == BottomSheetBehavior.STATE_EXPANDED) {
                              val displayMetrics = DisplayMetrics()
                              requireActivity().windowManager!!.defaultDisplay!!.getMetrics(displayMetrics)
                              (dialog as BottomSheetDialog).behavior.peekHeight = displayMetrics.heightPixels
                          } else {
                              (dialog as BottomSheetDialog).behavior.state = state
                          }
                      }
                  
                      override fun getTheme(): Int {
                          return R.style.CustomBottomSheetDialog
                      }
                  }
                  

                  CustomBottomSheetDialog 样式

                  <style name="CustomBottomSheetDialog" parent="@style/ThemeOverlay.MaterialComponents.BottomSheetDialog">
                      <item name="bottomSheetStyle">@style/CustomBottomSheet</item>
                      <item name="materialButtonStyle">@style/CustomMaterialButtonStyle</item>
                  </style>
                  
                  <style name="CustomMaterialButtonStyle" parent="@style/Widget.MaterialComponents.Button">
                      <item name="cornerRadius">@dimen/dialog_bottom_radius</item>
                  </style>
                  
                  <style name="CustomBottomSheet" parent="Widget.MaterialComponents.BottomSheet">
                      <item name="shapeAppearanceOverlay">@style/CustomShapeAppearanceBottomSheetDialog</item>
                  </style>
                  
                  <style name="CustomShapeAppearanceBottomSheetDialog" parent="">
                      <item name="android:background">@android:color/transparent</item>
                      <item name="backgroundTint">@android:color/transparent</item>
                      <item name="cornerFamily">rounded</item>
                      <item name="cornerSizeTopRight">@dimen/dialog_bottom_radius</item>
                      <item name="cornerSizeTopLeft">@dimen/dialog_bottom_radius</item>
                      <item name="cornerSizeBottomRight">0dp</item>
                      <item name="cornerSizeBottomLeft">0dp</item>
                  </style>
                  

                  【讨论】:

                  • 完美的答案就像魅力一样! :)
                  【解决方案24】:

                  对我有用的最简单和最干净的解决方案是将以下 3 行放入我的片段类的 onViewCreated(View view, Bundle savedInstanceState) 方法中:

                  @Override
                  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
                      View bottomSheet = (View) view.getParent();
                      bottomSheet.setBackgroundTintMode(PorterDuff.Mode.CLEAR);
                      bottomSheet.setBackgroundTintList(ColorStateList.valueOf(Color.TRANSPARENT));
                      bottomSheet.setBackgroundColor(Color.TRANSPARENT);
                  }
                  

                  这将允许您的带有圆角的自定义可绘制对象在设置为片段布局的顶级视图的背景后正确显示。

                  本质上,这会覆盖关于颜色、tintMode 和 tintList 的默认 BottomSheetFragment 属性。

                  使用这个,就不用乱搞样式资源了。

                  【讨论】:

                    【解决方案25】:

                    首先,您应该创建一个可绘制的 xml 文件,其中包含一个顶部圆角的形状,您可以随意命名。 我将其命名为底部 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>
                    

                    【讨论】:

                      猜你喜欢
                      • 2019-10-01
                      • 2019-06-03
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-03-30
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多