如何使用钻石式 FAB?

8
如何在底部应用栏中使用钻石样式和浮动操作按钮?在网站https://material.io/tools/theme-editor/上的草图文件中,有这样的样式fab: enter image description here 查看了所有可能的样式和标签...

1
我怀疑你必须自己创建它,可能使用自定义背景。我在Material Components的FloatingActionButton中没有看到任何形状相关的内容。 - CommonsWare
@CommonsWare 我认为我不应该自己创建它... 它与底部应用栏和消失动画一起工作。 - RomanK.
2
嗯,有Material Components 1.1中的EdgeTreatment和CornerTreatment的MaterialShapeDrawable,但需要一些时间来学习API并制作出漂亮的东西。 - Zielony
2个回答

5

目前还没有官方的形状可以用于BottomAppBar

然而,在版本为1.1.0Material Components库中,您可以使用app:shapeAppearance属性自定义FloatingActionButton形状

您可以使用类似以下内容的代码:

 <com.google.android.material.floatingactionbutton.FloatingActionButton
        app:layout_anchor="@id/bar"
        app:shapeAppearance="@style/FabDiamondOverlay"
        .../>

采用这种样式:

 <style name="FabDiamondOverlay" parent="">
    <item name="cornerFamily">cut</item>
    <item name="cornerSize">8dp</item>
  </style>

这是结果:

enter image description here

目前,形状主题属性不会影响BottomAppBar,您只能为FAB cradle设置圆角。在官方存储库中添加了解决方法

只需使用带有属性app:fabCradleMargin的默认BottomAppBar(它定义了FloatingActionButtonBottomAppBar之间的距离)

<com.google.android.material.bottomappbar.BottomAppBar
        android:id="@+id/bar"
        ...
        android:layout_gravity="bottom"
        app:fabCradleMargin="10dp"
        />

使用BottomAppBarTopEdgeTreatment来改变BottomAppBar的形状:

    BottomAppBar bar = findViewById(R.id.bar);
    FloatingActionButton fab2 = findViewById(R.id.fab);
    BottomAppBarTopEdgeTreatment topEdge = new BottomAppBarCutCornersTopEdge(
            bar.getFabCradleMargin(),
            bar.getFabCradleRoundedCornerRadius(),
            bar.getCradleVerticalOffset());
    MaterialShapeDrawable babBackground = (MaterialShapeDrawable) bar.getBackground();
    //It requires 1.1.0-alpha10
    babBackground.setShapeAppearanceModel(
      babBackground.getShapeAppearanceModel()
      .toBuilder()
      .setTopEdge(topEdge)
      .build());

这是最终结果:

输入图像描述此处


我在问题创建后立即完成了它 :) 你如何包装边缘? - RomanK.
你的意思是从fab的形状开始自动更改bottombar的边缘吗? - Gabriele Mariotti
我们需要使角落看起来像屏幕截图一样。它们是圆角的,而不是尖锐的。 - RomanK.
如果您想制作类似于截图的角落,请使用答案中提供的代码和 此类,它可以包裹边缘。否则,对于圆角或平角,只需使用标准组件即可。 - Gabriele Mariotti
1
@RomanK。我不确定我的评论是否清晰,以及您是否能够在栏杆中包裹边缘。 - Gabriele Mariotti

1

向Gabriele Mariotti致敬。我使用了他的代码并稍微修改了一下,以使底部应用栏具有原始问题中的圆角外观。

首先,对于FAB,我给它圆形角落并将其旋转45度,如下所示:

FAB的XML代码:

<com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/fabHome"
        android:rotation="45"
        app:layout_anchor="@id/bottomBarHome"
        app:shapeAppearanceOverlay="@style/FabDiamondOverlay"/>

FabDiamondOverlay 是:

<style name="FabDiamondOverlay" parent="">
    <item name="cornerFamily">rounded</item>
    <item name="cornerSize">15%</item>
</style>

which gives the resulting FAB:

Diamond rounded FAB

现在是底部栏的XML代码:
<com.google.android.material.bottomappbar.BottomAppBar
        android:id="@+id/bottomBarHome"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:backgroundTint="@color/grey"
        app:fabCradleMargin="20dp"
        app:fabCradleVerticalOffset="5dp"
        android:layout_gravity="bottom" />

在OnCreate方法中添加以下代码,以使底部应用栏具有自定义外观:

    BottomAppBar bar = findViewById(R.id.bottomBarHome);

    BottomAppBarTopEdgeTreatment topEdge = new BottomAppBarCutCornersTopEdge(
            bar.getFabCradleMargin(),
            bar.getFabCradleRoundedCornerRadius(),
            bar.getCradleVerticalOffset());

    MaterialShapeDrawable bottomBarBackground = (MaterialShapeDrawable) bar.getBackground();
    bottomBarBackground.setShapeAppearanceModel(
            bottomBarBackground.getShapeAppearanceModel()
                    .toBuilder()
                    .setTopRightCorner(CornerFamily.ROUNDED,75)
                    .setTopLeftCorner(CornerFamily.ROUNDED,75)
                    .setTopEdge(topEdge)
                    .build());

在修改Gabrielle的代码时,BottomAppBarCutCornersTopEdge是所需内容:Source">源代码

@Override
    @SuppressWarnings("RestrictTo")
    public void getEdgePath(float length, float center, float interpolation, ShapePath shapePath) {
        float fabDiameter = getFabDiameter();
        if (fabDiameter == 0) {
            shapePath.lineTo(length, 0);
            return;
        }

        float diamondSize = fabDiameter / 2f;
        float middle = center + getHorizontalOffset();

        float verticalOffsetRatio = cradleVerticalOffset / diamondSize;
        if (verticalOffsetRatio >= 1.0f) {
            shapePath.lineTo(length, 0);
            return;
        }

        float barLeftVertex = middle - (fabMargin + diamondSize - cradleVerticalOffset);
        float barRightVertex = middle + (fabMargin + diamondSize - cradleVerticalOffset);
        float depth = (diamondSize - cradleVerticalOffset + fabMargin) * interpolation;

        float heightArc = 25;
        float widthArc = 25;

        shapePath.lineTo(barLeftVertex, 0);

        shapePath.lineTo(middle-widthArc, depth-heightArc);

        shapePath.addArc(middle-widthArc-10, 35, middle+widthArc+10, depth-15, 135, -83);

        shapePath.lineTo(middle+widthArc, depth-heightArc);
        shapePath.lineTo(barRightVertex, 0);

        shapePath.lineTo(length, 0);
    }

这里的数值是通过试错法确定的。我无法理解每个变量的作用,而且关于此方面的文档似乎非常少。但它能够完成工作!以下是最终结果:

Final image


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接