圆角背景的实现

1. xml里写shape

这种大家比较熟了,最基础的使用了

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="25dp" />
    <solid android:color="#ff0000" />
</shape>

2. java代码生成drawable

如下一个简单的圆角矩形,

var shape=RoundRectShape(floatArrayOf(10f,10f,10f,10f,10f,10f,10f,10f),null,null);
        var drawble=ShapeDrawable(shape).apply { setColorFilter(Color.RED,PorterDuff.Mode.SRC_IN) }
        tv_test.background=drawble
        var pD=PaintDrawable(Color.RED);
        pD.setCornerRadius(20f);
        tv_test2.background=pD;

其实xml里能有的drawalbe,java代码都有对应的,我们这里只看圆角矩形
没找到stroke咋设置,等有空再看看

3 outline

对于21以上 的版本

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            findViewById(R.id.iv_temp).setClipToOutline(true);
            findViewById(R.id.iv_temp).setOutlineProvider(new ViewOutlineProvider() {
                @Override
                public void getOutline(View view, Outline outline) {
                    outline.setRoundRect(0,0,view.getWidth(),view.getHeight(),20);
                }
            });
        }

4. 自定义形状

我们就是参考系统的这个来写


image.png

代碼如下

        <com.google.android.material.bottomappbar.BottomAppBar
            android:id="@+id/bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            app:menu="@menu/menu_nav_bottom"
            app:backgroundTint="#673AB7"
            app:fabAlignmentMode="end"
            app:fabAnimationMode="slide"
            app:fabCradleVerticalOffset="0dp"
            app:fabCradleMargin="5dp"
            app:fabCradleRoundedCornerRadius="10dp"
            app:navigationIcon="@drawable/iv_leaf_1"/>

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/iv_leaf_3"
            app:layout_anchor="@id/bar"/>

看了下源码,实现如下


image.png

跟我们参数有关主要就是BottomAppBarTopEdgeTreatment类了,不过看了下这类如下两个设置fab直径以及凹槽偏移量的方法不是公用的。瞅了眼这个类也没几行代码,那就复制下这个类,把下边两个方法弄成公共的就完事了

  @RestrictTo(LIBRARY_GROUP)
  public void setFabDiameter(float fabDiameter) {
    this.fabDiameter = fabDiameter;
  }

  /** Sets the horizontal offset, in pixels, of the cradle from center. */
  void setHorizontalOffset(float horizontalOffset) {
    this.horizontalOffset = horizontalOffset;
  }

最终代码如下
BottomNavViewTopEdgeTreatment类 就是修改的系统类

private val materialShapeDrawable = MaterialShapeDrawable()
        val topEdgeTreatment: EdgeTreatment = BottomNavViewTopEdgeTreatment(10f, 5f, 0f)

        val shapeAppearanceModel = ShapeAppearanceModel.builder().setTopEdge(topEdgeTreatment)
                .setAllCornerSizes(30f)
                .build()

        materialShapeDrawable.shapeAppearanceModel = shapeAppearanceModel
        materialShapeDrawable.shadowCompatibilityMode = MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYS
        materialShapeDrawable.paintStyle = Paint.Style.FILL
        materialShapeDrawable.interpolation=1f
        materialShapeDrawable.initializeElevationOverlay(this)
        DrawableCompat.setTintList(materialShapeDrawable, ColorStateList.valueOf(Color.GREEN));

        getTopEdgeTreatment()?.horizontalOffset=0f;//默认凹槽在正中心,这里可以左右偏移
        getTopEdgeTreatment()?.fabDiameter=60f//就是那个floatingActionBar的直径
        ViewCompat.setBackground(bottomView, materialShapeDrawable)

ShapeAppearanceModel这个类可以简单看下,可以设置四条边的path,我们这里就设置的是top,完事还可以设置4个圆角半径,

相关代码,都是系统原生的

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomView"
        android:layout_width="300dp"
        android:layout_height="60dp"
android:layout_marginTop="100dp"
        app:menu="@menu/menu_nav_bottom2" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@drawable/iv_leaf_3"
        app:layout_anchor="@id/bottomView" />

menu
menu_nav_bottom2.xml 中间那个隐藏了,不可用,就占位用

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/settings_fragment"
        android:icon="@drawable/iv_leaf_1"
        android:title="settings"
        app:showAsAction="always" />
    <item
        android:id="@+id/second_fragment"
        android:enabled="false"
        android:icon="@null"
        android:title="@null" />
    <item
        android:id="@+id/third_fragment"
        android:icon="@drawable/iv_leaf_3"
        android:title="third"
        app:showAsAction="always" />
</menu> 

效果图


image.png

学完这个,以后复杂形状自己也能模仿这里的path自己弄出来了
其他字段的解释,以前有篇帖子研究过BottomAppBar,这几个属性有说明
fabMargin :就是fab和凹槽之间的间隔距离
roundedCornerRadius :这个是凹槽那个圆弧和横线之间还有个圆弧的,就是那个圆弧的半径
cradleVerticalOffset :凹槽的偏移量,为0的话凹槽刚好是个半圆,为正的话凹槽上移,为负抛出异常

  /**
   * @param fabMargin the margin in pixels between the cutout and the fab.
   * @param roundedCornerRadius the radius, in pixels, of the rounded corners created by the cutout.
   *     A value of 0 will produce a sharp cutout.
   * @param cradleVerticalOffset vertical offset, in pixels, of the {@link FloatingActionButton}
   *     being cradled. An offset of 0 indicates the vertical center of the {@link
   *     FloatingActionButton} is positioned on the top edge.
   */
  public BottomAppBarTopEdgeTreatment(
      float fabMargin, float roundedCornerRadius, float cradleVerticalOffset)

参考:
https://www.jianshu.com/p/8cd6add34f19
写不了太复杂的path,一会就晕了,所以就偷懒用系统写好的,修修补补就可以用了。

看下一些系统控件的使用:

  1. MaterialButton
ShapeAppearanceModel shapeAppearanceModel =
        ShapeAppearanceModel.builder(context, attrs, defStyleAttr, DEF_STYLE_RES).build();

  private void updateButtonShape(@NonNull ShapeAppearanceModel shapeAppearanceModel) {
    if (getMaterialShapeDrawable() != null) {
      getMaterialShapeDrawable().setShapeAppearanceModel(shapeAppearanceModel);
    }
    if (getSurfaceColorStrokeDrawable() != null) {
      getSurfaceColorStrokeDrawable().setShapeAppearanceModel(shapeAppearanceModel);
    }
    if (getMaskDrawable() != null) {
      getMaskDrawable().setShapeAppearanceModel(shapeAppearanceModel);
    }
  }
  1. CardView
    这里用的是RoundRectDrawable
    public void initialize(CardViewDelegate cardView, Context context,
                ColorStateList backgroundColor, float radius, float elevation, float maxElevation) {
        final RoundRectDrawable background = new RoundRectDrawable(backgroundColor, radius);
        cardView.setCardBackground(background);

        View view = cardView.getCardView();
        view.setClipToOutline(true);
        view.setElevation(elevation);
        setMaxElevation(cardView, maxElevation);
    }
  1. MaterialCardView
//MaterialCardViewHelper
    bgDrawable = new MaterialShapeDrawable(card.getContext(), attrs, defStyleAttr, defStyleRes);
    bgDrawable.initializeElevationOverlay(card.getContext());
    bgDrawable.setShadowColor(Color.DKGRAY);
    ShapeAppearanceModel.Builder shapeAppearanceModelBuilder =
        bgDrawable.getShapeAppearanceModel().toBuilder();

另外我们使用这个控件的时候发现它只提供了一个radius的设置,也就是只能4个圆角一样

<com.google.android.material.card.MaterialCardView
    app:cardCornerRadius="10dp"

实际上可以设置4个不同的圆角的,另外上边那个cardCornerRadius优先级比较高

<com.google.android.material.card.MaterialCardView
    app:shapeAppearance="@style/cornerCustom"

app:shapeAppearance如下

    <style name="cornerCustom">
        <item name="cornerSizeTopRight">20dp</item>
        <item name="cornerSizeBottomRight">20dp</item>
    </style>

至于完整的属性可以参考ShapeAppearanceModel

      int cornerFamily = a.getInt(R.styleable.ShapeAppearance_cornerFamily, CornerFamily.ROUNDED);
      int cornerFamilyTopLeft =
          a.getInt(R.styleable.ShapeAppearance_cornerFamilyTopLeft, cornerFamily);
      int cornerFamilyTopRight =
          a.getInt(R.styleable.ShapeAppearance_cornerFamilyTopRight, cornerFamily);
      int cornerFamilyBottomRight =
          a.getInt(R.styleable.ShapeAppearance_cornerFamilyBottomRight, cornerFamily);
      int cornerFamilyBottomLeft =
          a.getInt(R.styleable.ShapeAppearance_cornerFamilyBottomLeft, cornerFamily);

      CornerSize cornerSize =
          getCornerSize(a, R.styleable.ShapeAppearance_cornerSize, defaultCornerSize);

      CornerSize cornerSizeTopLeft =
          getCornerSize(a, R.styleable.ShapeAppearance_cornerSizeTopLeft, cornerSize);
      CornerSize cornerSizeTopRight =
          getCornerSize(a, R.styleable.ShapeAppearance_cornerSizeTopRight, cornerSize);
      CornerSize cornerSizeBottomRight =
          getCornerSize(a, R.styleable.ShapeAppearance_cornerSizeBottomRight, cornerSize);
      CornerSize cornerSizeBottomLeft =
          getCornerSize(a, R.styleable.ShapeAppearance_cornerSizeBottomLeft, cornerSize);

另外看下CornerFamily的效果,默认就是Rounded圆角,还有一种是Cut,如下

    <style name="cornerCustom">
        <item name="cornerSizeTopRight">40dp</item>
        <item name="cornerSizeBottomRight">40dp</item>
        <item name="cornerFamilyTopRight">cut</item>
    </style>
image.png
  1. Chip
    系统默认的是两边半圆,提供了一个属性可以修改圆角,不过圆角都一样的
    要是想让圆角不一样,那么也可以通过设置app:shapeAppearance来实现
<com.google.android.material.chip.Chip

后记

对于不支持ShapeAppearanceModel的控件,那么用MaterialShapeDrawable也可以,给它设置个ShapeAppearanceModel就行了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容