当前位置:首页 > 谈天说地 > 正文内容

Android中ShapeableImageView使用实例详解(告别shape、三方库)

34资源网2022年09月05日 09:42199
站长推荐》》》》》摆摊地推这两款软件,一个月3000元-3万元轻松实现《《《《《站长推荐

效果

前言

先来看一下shapeableimageview是什么

由上图可以看到shapeableimageview也没有什么神秘的,不过是imageview的一个子类而已,但是从效果图来看,在不写shape、不引入三方库的情况下,还是挺容易实现预期效果的,而且扩展性良好。

使用

引入material包

implementation 'com.google.android.material:material:1.2.1'

常规

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:src="@mipmap/ic_avatar" />

和imageview正常使用没有区别

圆角

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:src="@mipmap/ic_avatar"
    app:shapeappearance="@style/roundedstyle" />
<!--shapeableimageview 圆角-->
<style name="roundedstyle">
    <item name="cornerfamily">rounded</item>
    <item name="cornersize">10dp</item>
</style>
  • 没有直接设置圆角的属性,需要用到app:shapeappearance,后面会说
  • cornerfamily 角的处理方式,rounded圆角,cut裁剪
  • cornersize 圆角大小

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:src="@mipmap/ic_avatar"
    app:shapeappearance="@style/circlestyle" />
<!--shapeableimageview 圆 -->
<style name="circlestyle">
    <item name="cornerfamily">rounded</item>
    <item name="cornersize">50%</item>
</style>

圆角的大小可以用百分比,也可以自己计算,比如宽高100dp,圆角50dp

描边

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp" 
    android:padding="2dp"
    android:src="@mipmap/ic_avatar"
    app:shapeappearance="@style/circlestyle"
    app:strokecolor="@color/red"
    app:strokewidth="4dp" />
  • app:strokecolor 描边颜色
  • app:strokewidth 描边宽度
  • 注意这里padding的数值是描边宽度的一半,后面会说

切角

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp" 
    android:padding="2dp"
    android:src="@mipmap/ic_avatar"
    app:shapeappearance="@style/cutstyle"
    app:strokecolor="@color/red"
    app:strokewidth="4dp" />
<!--shapeableimageview 切角 -->
<style name="cutstyle">
    <item name="cornerfamily">cut</item>
    <item name="cornersize">10dp</item>
</style>

cornerfamily:cut 处理模式变为裁剪

菱形

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp" 
    android:padding="2dp"
    android:src="@mipmap/ic_avatar"
    app:shapeappearance="@style/rhombusstyle"
    app:strokecolor="@color/red"
    app:strokewidth="4dp" />
<!--shapeableimageview 菱形 -->
<style name="rhombusstyle">
    <item name="cornerfamily">cut</item>
    <item name="cornersize">50%</item>
</style>

同样,裁剪模式下圆角大小也可以计算

叶子

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp" 
    android:padding="2dp"
    android:src="@mipmap/ic_avatar"
    app:shapeappearance="@style/leafstyle"
    app:strokecolor="@color/red"
    app:strokewidth="4dp" />
<!--shapeableimageview 叶子 -->
<style name="leafstyle">
    <item name="cornerfamily">rounded</item>
    <item name="cornersizetopleft">50%</item>
    <item name="cornersizebottomright">50%</item>
</style>
  • cornersizetopleft 左上圆角
  • cornersizebottomright 右下圆角
  • 以此类推,左上、左下、右上、右下等

半圆

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp" 
    android:padding="2dp"
    android:src="@mipmap/ic_avatar"
    app:shapeappearance="@style/semicirclestyle"
    app:strokecolor="@color/red"
    app:strokewidth="4dp" />
<!--shapeableimageview 半圆 -->
<style name="semicirclestyle">
    <item name="cornerfamily">rounded</item>
    <item name="cornersizetopleft">50%</item>
    <item name="cornersizetopright">50%</item>
</style>

六边形

<com.google.android.material.imageview.shapeableimageview
    android:layout_width="wrap_content"
    android:layout_height="50dp"
    android:layout_margin="10dp" 
    android:padding="2dp"
    android:scaletype="centercrop"
    android:src="@mipmap/ic_avatar"
    app:shapeappearance="@style/hexagonstyle"
    app:strokecolor="@color/red"
    app:strokewidth="4dp" />
<!--shapeableimageview 六边形 -->
<style name="hexagonstyle">
    <item name="cornerfamily">cut</item>
    <item name="cornersizetopleft">50%</item>
    <item name="cornersizetopright">50%</item>
    <item name="cornersizebottomleft">50%</item>
    <item name="cornersizebottomright">50%</item>
</style>

属性

关于xml属性,我也做了一个整理,属性不多,只有4个

属性 描述
strokewidth 描边宽度
strokecolor 描边颜色
shapeappearance 外观样式
shapeappearanceoverlay 同上,叠加层

扩展

前面为了整体的排版,埋了几个伏笔,下面来一一解答。

会涉及到源码,但是经过去繁从简,看起来也非常轻松的。

shapeappearance

shape appearance overlay style reference for shapeableimageview.
shapeableimageview的形状外观覆盖样式参考。

前面可以看到我们设置圆角其实是用的style,那为什么不直接用attrs呢,不是更加直观方便吗,带着疑问来看看源码是怎么处理的。

直接看shapeableimageview的次构造方法:

public class shapeableimageview extends appcompatimageview implements shapeable {

  ...

  public shapeableimageview(context context, @nullable attributeset attrs, int defstyle) {
    super(wrap(context, attrs, defstyle, def_style_res), attrs, defstyle);
    // ensure we are using the correctly themed context rather than the context that was passed in.
    context = getcontext();

    clearpaint = new paint();
    clearpaint.setantialias(true);
    clearpaint.setcolor(color.white);
    clearpaint.setxfermode(new porterduffxfermode(mode.dst_out));
    destination = new rectf();
    maskrect = new rectf();
    maskpath = new path();
    typedarray attributes =
        context.obtainstyledattributes(
            attrs, r.styleable.shapeableimageview, defstyle, def_style_res);

    strokecolor =
        materialresources.getcolorstatelist(
            context, attributes, r.styleable.shapeableimageview_strokecolor);

    strokewidth = attributes.getdimensionpixelsize(r.styleable.shapeableimageview_strokewidth, 0);

    borderpaint = new paint();
    borderpaint.setstyle(style.stroke);
    borderpaint.setantialias(true);
    shapeappearancemodel =
        shapeappearancemodel.builder(context, attrs, defstyle, def_style_res).build();
    shadowdrawable = new materialshapedrawable(shapeappearancemodel);
    if (version.sdk_int >= version_codes.lollipop) {
      setoutlineprovider(new outlineprovider());
    }
  }
}

常规操作,获取自定义属性。

关键的两行代码:

    shapeappearancemodel = shapeappearancemodel.builder(context, attrs, defstyle, def_style_res).build();
    shadowdrawable = new materialshapedrawable(shapeappearancemodel);

也就是说我们给shapeappearance设置的style,并不是shapeableimageview自己来处理的,而是由shapeappearancemodel来构建的,然后又交给materialshapedrawable来绘制的。

shapeappearancemodel

这个类就厉害了,有点像flutter中的decoration,可以构建出花里胡哨的效果。

来看shapeappearancemodel部分源码:

public class shapeappearancemodel {

  /** builder to create instances of {@link shapeappearancemodel}s. */
  public static final class builder {

    @nonnull
    private cornertreatment topleftcorner = materialshapeutils.createdefaultcornertreatment();

    @nonnull
    private cornertreatment toprightcorner = materialshapeutils.createdefaultcornertreatment();

    @nonnull
    private cornertreatment bottomrightcorner = materialshapeutils.createdefaultcornertreatment();

    @nonnull
    private cornertreatment bottomleftcorner = materialshapeutils.createdefaultcornertreatment();

    @nonnull private cornersize topleftcornersize = new absolutecornersize(0);
    @nonnull private cornersize toprightcornersize = new absolutecornersize(0);
    @nonnull private cornersize bottomrightcornersize = new absolutecornersize(0);
    @nonnull private cornersize bottomleftcornersize = new absolutecornersize(0);

    @nonnull private edgetreatment topedge = materialshapeutils.createdefaultedgetreatment();
    @nonnull private edgetreatment rightedge = materialshapeutils.createdefaultedgetreatment();
    @nonnull private edgetreatment bottomedge = materialshapeutils.createdefaultedgetreatment();
    @nonnull private edgetreatment leftedge = materialshapeutils.createdefaultedgetreatment();

    public builder() {}
    ...
  }
  ...
}

可以看到有各种边和角的属性,这里注意两个点:

  • materialshapeutils.createdefaultcornertreatment() 创建默认角的处理方式
  • materialshapeutils.createdefaultedgetreatment() 创建默认边的处理方式

也就意味着,边和角除了默认,是可以自定义的,这就有极大的想象空间了,

比如这样:

// 代码设置 角和边
val shapeappearancemodel2 = shapeappearancemodel.builder().apply {
    setallcorners(roundedcornertreatment())
    setallcornersizes(50f)
    setalledges(triangleedgetreatment(50f, false))
}.build()
val drawable2 = materialshapedrawable(shapeappearancemodel2).apply {
    settint(contextcompat.getcolor(this@shapeableimageviewactivity, r.color.colorprimary))
    paintstyle = paint.style.fill_and_stroke
    strokewidth = 50f
    strokecolor = contextcompat.getcolorstatelist(this@shapeableimageviewactivity, r.color.red)
}
mbinding.text2.settextcolor(color.white)
mbinding.text2.background = drawable2

再比如这样:

// 代码设置 聊天框效果
val shapeappearancemodel3 = shapeappearancemodel.builder().apply {
    setallcorners(roundedcornertreatment())
    setallcornersizes(20f)
    setrightedge(object : triangleedgetreatment(20f, false) {
        // center 位置 , interpolation 角的大小
        override fun getedgepath(length: float, center: float, interpolation: float, shapepath: shapepath) {
            super.getedgepath(length, 35f, interpolation, shapepath)
        }
    })
}.build()
val drawable3 = materialshapedrawable(shapeappearancemodel3).apply {
    settint(contextcompat.getcolor(this@shapeableimageviewactivity, r.color.colorprimary))
    paintstyle = paint.style.fill
}
(mbinding.text3.parent as viewgroup).clipchildren = false // 不限制子view在其范围内
mbinding.text3.settextcolor(color.white)
mbinding.text3.background = drawable3

materialshapedrawable

源码(有删减):

public class materialshapedrawable extends drawable implements tintawaredrawable, shapeable {
...
  @override
  public void draw(@nonnull canvas canvas) {
    fillpaint.setcolorfilter(tintfilter);
    final int prevalpha = fillpaint.getalpha();
    fillpaint.setalpha(modulatealpha(prevalpha, drawablestate.alpha));

    strokepaint.setcolorfilter(stroketintfilter);
    strokepaint.setstrokewidth(drawablestate.strokewidth);

    final int prevstrokealpha = strokepaint.getalpha();
    strokepaint.setalpha(modulatealpha(prevstrokealpha, drawablestate.alpha));

    if (pathdirty) {
      calculatestrokepath();
      calculatepath(getboundsasrectf(), path);
      pathdirty = false;
    }

    maybedrawcompatshadow(canvas);
    if (hasfill()) {
      drawfillshape(canvas);
    }
    if (hasstroke()) {
      drawstrokeshape(canvas);
    }
...
  static final class materialshapedrawablestate extends constantstate {
    ...
    public materialshapedrawablestate(@nonnull materialshapedrawablestate orig) {
      shapeappearancemodel = orig.shapeappearancemodel;
      elevationoverlayprovider = orig.elevationoverlayprovider;
      strokewidth = orig.strokewidth;
      colorfilter = orig.colorfilter;
      fillcolor = orig.fillcolor;
      strokecolor = orig.strokecolor;
      tintmode = orig.tintmode;
      tintlist = orig.tintlist;
      alpha = orig.alpha;
      scale = orig.scale;
      shadowcompatoffset = orig.shadowcompatoffset;
      shadowcompatmode = orig.shadowcompatmode;
      usetintcolorforshadow = orig.usetintcolorforshadow;
      interpolation = orig.interpolation;
      parentabsoluteelevation = orig.parentabsoluteelevation;
      elevation = orig.elevation;
      translationz = orig.translationz;
      shadowcompatradius = orig.shadowcompatradius;
      shadowcompatrotation = orig.shadowcompatrotation;
      stroketintlist = orig.stroketintlist;
      paintstyle = orig.paintstyle;
      if (orig.padding != null) {
        padding = new rect(orig.padding);
      }
    }
	...
  }
...
}

没什么特别的,你只需要知道除了可以设置描边之外,还可以设置背景、阴影等其他属性。

说明

  • shapeappearancemodel只能是实现shapeable接口的view才可以设置,比如chipmaterialbuttom等。
  • materialshapedrawable其实就是drawable,是所有view都可以设置的。

描边问题

这里借github一张图

又是自定义view的常规操作,有一半画笔是在边界外面的,所以需要设置paddingstrokewidth的一半。

默认圆角问题

有细心的同学会发现啊,第一个常规的shapeableimageview还是有一点圆角的,没错,属于默认的,跟踪一下源码来看一下:

<style name="widget.materialcomponents.shapeableimageview" parent="android:widget">
    <item name="strokecolor">@color/material_on_surface_stroke</item>
    <item name="shapeappearance">?attr/shapeappearancemediumcomponent</item>
</style>

第一个是颜色,很明显不是我们要找的,继续看shapeappearancemediumcomponent

<attr format="reference" name="shapeappearancemediumcomponent"/>

只是一个简单的属性,继续查找关联引用

    <item name="shapeappearancemediumcomponent">
      @style/shapeappearance.materialcomponents.mediumcomponent
    </item>

又引用了一个style,继续看shapeappearance.materialcomponents.mediumcomponent这个style

<style name="shapeappearance.materialcomponents.mediumcomponent">
    <item name="cornersize">@dimen/mtrl_shape_corner_size_medium_component</item>
</style>

哦豁,看到了熟悉的属性cornersize,藏的还挺深,继续看看数值是多少

<dimen name="mtrl_shape_corner_size_medium_component">4dp</dimen>

默认4dp

那如果不想要这个圆角怎么办呢,可以学习源码仿写一个,不过上面也看到了,有点绕,不如直接写个style搞定:

    <!--shapeableimageview 去圆角-->
    <style name="corner0style">
        <item name="cornersize">0dp</item>
    </style>

然后引用

app:shapeappearance="@style/corner0style"

效果:

ok,到这里就差不多了,虽然还有很多相关知识点没有提及,但是也不少了,不如自己去尝试一番,慢慢消化。

github

https://github.com/yechaoa/materialdesign

感谢

  • shapeableimageview 官方文档
  • shapeappearancemodel 官方文档
  • android material组件使用详解
  • android notes|玩转 shapeableimageview
  • material components——shape的处理

最后

到此这篇关于android中shapeableimageview使用详解的文章就介绍到这了,更多相关android shapeableimageview使用内容请搜索萬仟网以前的文章或继续浏览下面的相关文章希望大家以后多多支持萬仟网!

看完文章,还可以用支付宝扫描下面的二维码领取一个支付宝红包,目前可领1-88元不等

支付宝红包二维码

除了扫码可以领取之外,大家还可以(复制 720087999 打开✔支付宝✔去搜索, h`o`n.g.包哪里来,动动手指就能领)。

看下图所示是好多参与这次活动领取红包的朋友:

支付宝红包

扫描二维码推送至手机访问。

版权声明:本文由34楼发布,如需转载请注明出处。

本文链接:https://www.34l.com/post/21675.html

分享给朋友:

相关文章

智能电视和普通电视的区别,智能电视好还是普通电视好?
智能电视和普通电视的区别,智能电视好还是普通电视好?

好多人对智能电视和普通的区别还分不大清楚,今天小编就将智能电视和和普通电视做个简单明了的介绍,希望对大家有所帮助。简单的讲,就是智能电视可以看直播电视,也可以点播一些网络电视来看,这个就是最大的区别。当然,有些智能电视还有储存功能,比如,可...

抱怨是一种毒药,比较有深度的好文
抱怨是一种毒药,比较有深度的好文

问:怎么每天 都能免费收到这种 好文章呢?烦恼的根源都在自己生气,是因为你不够大度;郁闷,是因为你不够豁达;焦虑,是因为你不够从容;悲伤,是因为你不够坚强;惆怅,是因为你不够阳光;嫉妒,是因为你不够优秀。凡此种种烦恼的根源都在自己这里,所以...

怎么用兴趣造句?15句关于兴趣的造句示例
怎么用兴趣造句?15句关于兴趣的造句示例

很多人不知道怎么用兴趣造句?下面小编整理了15句关于兴趣的造句示例希望对大家有所帮助。关于兴趣的造句:1、作为一个导演,离开自己兴趣的东西他都可以剪掉。我今天可以告诉你,没有一个字,不是我的兴趣。2、在劳动中获得的喜悦是特别的,绝对不是游玩...

应用汇下载安装最新版(2021最新版应用汇app)
应用汇下载安装最新版(2021最新版应用汇app)

Donews8月17日消息(记者 邱慧)近日,为安卓手机服务的应用型软件“应用汇”新版正式上线,同时推出“应用收藏”功能——“应用集”。 应用集主要分为“推荐”、“最热”、“最新”三类。应用汇官方介绍,此次新版上线后,安装包被优化缩小,...

哪家的云主机好(国内五大云主机服务商)
哪家的云主机好(国内五大云主机服务商)

导言:博睿数据(股票代码688229)十余年专注APM领域,已为超过2000余家大型企业提供专业数据服务。依托先进的测评技术及丰富的行业经验,博睿宏远倾力打造了一个公开透明的性能测评栏目——【Bonree指数】。该栏目致力于呈现各行业的整体...

融资丨「大湾生物」完成近千万美元A轮融资,比邻星创投及高瓴创投共同领投
融资丨「大湾生物」完成近千万美元A轮融资,比邻星创投及高瓴创投共同领投

创业邦获悉,近日,大湾生物有限公司(以下简称:大湾生物)宣布完成近千万美元A轮融资,由比邻星创投与高瓴创投共同领投,阿隆资本跟投以及阿里巴巴香港创业者基金等现有投资者追加投资。本轮融资将加快大湾生物全球创新的三大人工智能平台,分别是智能化...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。