书接前文,我们讲了在MD Component中的MaterialShapeDrawable,今天则继续讲解在此基础上,MDC封装的一个Image组件——ShapeableImageView。它的作用就是让开发者方便的对Imageview加载的图像进行Shape的处理。
老规矩,官网文档镇楼。
https://developer.android.com/reference/com/google/android/material/imageview/ShapeableImageView
使用
ShapeableImageView的使用非常简单,与传统的Imageview类似,当然前提是需要引入MD Library。
implementation 'com.google.android.material:material:<version>'
首先,需要在xml中引入ShapeableImageView,并指定shapeAppearanceOverlay,代码如下所示。
<com.google.android.material.imageview.ShapeableImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/test"
app:shapeAppearanceOverlay="@style/ShapeAppearance.circle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
这个指定的shapeAppearanceOverlay,就是具体的Shape的处理,它是一个Style,下面通过几个例子来演示下如何创建这个Style。
Round Cut
在style中的内容即为需要处理的效果,这里指定了Corner的处理效果类型为rounded,同时指定了Corner大小为Image的10%(当然你也可以指定其它单位)。
<style name="ShapeAppearance.circle" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">10%</item>
</style>
展示效果如图所示,即最简单的圆角图像。
![](https://i-blog.csdnimg.cn/blog_migrate/4687e4199446e13384721e031b874142.png)
cornerSize可以设置多种不同的数值,比如百分百,dp等等。例如50%,即为圆形。
另外,在代码中可以这样设置。
val model = ShapeAppearanceModel.builder().setAllCornerSizes(ShapeAppearanceModel.PILL).build()
test.shapeAppearanceModel = model
同时,这样会覆盖xml中的shapeAppearanceOverlay。
在代码中的处理应该更为常用,而且从这里我们也可以发现,ShapeableImageView实际上就是采用的ShapeAppearanceModel来进行Shape的处理的。
直线Cut
再看下另一种Corner处理,代码如下所示。
<style name="ShapeAppearance.cut" parent="">
<item name="cornerFamily">cut</item>
<item name="cornerSize">10%</item>
</style>
即对Corner进行直角裁剪,效果如图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/2558dc9050338ef0170ec1c7a67b4e1d.png)
例如设置50%,即为裁剪成菱形。
混合
多种效果,在Style中可以和具体指定的Corner混合作用,产生不同的效果,代码如下所示。
<style name="ShapeAppearance.mix" parent="">
<item name="cornerFamilyTopLeft">rounded</item>
<item name="cornerFamilyBottomRight">cut</item>
<item name="cornerSizeTopLeft">24%</item>
<item name="cornerSizeBottomRight">36%</item>
</style>
效果如图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/e47c5e170d196e41e87b9ea324294653.png)
描边
除了对Corner的处理之外,ShapeableImageView同样可以对边界进行描边处理,在ShapeableImageView中指定strokeWidth和strokeColor即可,代码如下所示。
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:strokeColor="@color/colorAccent"
app:strokeWidth="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/test" />
效果如图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/6414a3b4f4ba982c0de380017482424a.png)
同时,描边是可以和裁剪结合起来用的,代码如下所示。
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/test"
android:layout_width="200dp"
android:layout_height="200dp"
android:padding="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/ShapeAppearance.circle"
app:srcCompat="@drawable/test"
app:strokeColor="@color/colorAccent"
app:strokeWidth="4dp" />
效果如图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/37af33a13d601a7616902e5833247662.png)
关于描边宽度需要注意的是,和自定义View一样,描边的宽度是中心点在Layout边界,所以是Layout边界内外均分strokeWidth的,所以描边是可能超出Layout边界的,造成截断的效果,所以可以设置内padding来处理溢出。
ShapeableImageView裁剪的原理
ShapeableImageView的源码并不复杂,核心代码如下。
![](https://i-blog.csdnimg.cn/blog_migrate/36cccdcfc2b4184f409a74085d7b683c.png)
实际上,就是在5.0之上,使用ViewOutlineProvider来对Image进行裁剪。
ViewOutlineProvider
ViewOutlineProvider是Android在5.0之后提出的对Shape处理的标准API,其效率会比传统的通过Xfermode进行裁剪的方式高很多,代码如下所示。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
test.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
// outline.setRoundRect(0, 0, view.width, view.height, 32f)
// outline.setOval(0, 0, view.width, view.height)
}
}
test.clipToOutline = true
}
}
其中的两行注释代码,分别用于绘制圆角矩形和圆形,效果如下所示。
![](https://i-blog.csdnimg.cn/blog_migrate/411a1f5ccc9594574955084cc26d6d96.png)
![](https://i-blog.csdnimg.cn/blog_migrate/17390289b32914ffa2ea0ebc3c49f226.png)
除了这种最简单的处理外,ViewOutlineProvider还支持外凸多边形的设置,代码如下所示。
val path = Path()
view.elevation = 4f
path.moveTo(-20f, -20f)
path.lineTo(-20f, view.height.toFloat() + 20)
path.lineTo(view.width.toFloat() + 20, view.height.toFloat() + 20)
path.lineTo(view.width.toFloat() + 20, -20f)
path.close()
outline.setConvexPath(path)
可以用于绘制外边框、气泡边角和elevation阴影等效果。
![](https://i-blog.csdnimg.cn/blog_migrate/780916cb3baa68cdc5ac2d5f550d6b0b.png)
修仙
对于Android和Flutter相关技术感兴趣的朋友,可以添加我的微信,拉你进Flutter修仙群和Android开发群,微信号 Tomcat_xu。
这是我的网站 https://xuyisheng.top 这里有Flutter、Android、Kotlin的优质内容,欢迎大家访问。点击原文,一键直达。