在 Android 中圆形图片的设计随处可见,代码实现不外乎两类:
- 对加载的图片 drawable 进行圆形裁剪
- 对 ImageView 本身进行圆形裁剪
对于第一类,ImageView 的尺寸保持原形,如果设置了背景的话,背景依然可见。
第二类具体的实现方式又有很多种:ShapeableImageView 以及 ViewOutlineProvider 等
使用 Glide 裁剪 drawable
val options = RequestOptions().transform(RoundedCorners(radius))
Glide.with(this).load(imageUrl).apply(options).into(imageView)
ShapeableImageView
// layout.xml
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/shapeable_image_view"
android:layout_width="100dp"
android:layout_height="100dp"
app:shapeAppearance="@style/CircleStyle" />
// style.xml
<style name="CircleStyle">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">50%</item>
</style>
Glide.with(this).load(imageUrl).into(shapeableImageView)
- 使用 ShapeableImageView 需要依赖 material
- ShapeableImageView 不仅可以实现圆形,也可以实现其他形状,还可以设置边框等
shapeAppearance 也可以不使用 xml style,而是代码的方式动态实现:
shapeableImageView.shapeAppearanceModel = ShapeAppearanceModel.builder()
.setAllCornerSizes(radius).build()
Glide.with(this).load(imageUrl).into(shapeableImageView)
ViewOutlineProvider
imageView.apply {
setLayerType(View.LAYER_TYPE_SOFTWARE, null)
clipToOutline = true
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
val w = view.width - view.paddingLeft - view.paddingRight
val h = view.height - view.paddingTop - view.paddingBottom
val offsetHorizontal = (max(w, h) - h) / 2
val offsetVertical = (max(w, h) - w) / 2
val radius = min(w, h) / 2f
outline.setRoundRect(
view.paddingLeft + offsetHorizontal,
view.paddingTop + offsetVertical,
view.width - view.paddingRight - offsetHorizontal,
view.height - view.paddingBottom - offsetVertical,
radius
)
}
}
}
Glide.with(this).load(imageUrl).apply(options).into(imageView)
当然,也可以把 outlineProvider 封装成一个单独的类,这样就可以用于其他任何 View,而这正是 ViewOutlineProvider 的强大之处
import android.graphics.Outline
import android.view.View
import android.view.ViewOutlineProvider
import kotlin.math.max
import kotlin.math.min
class RoundedOutlineProvider : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
val w = view.width - view.paddingLeft - view.paddingRight
val h = view.height - view.paddingTop - view.paddingBottom
val offsetHorizontal = (max(w, h) - h) / 2
val offsetVertical = (max(w, h) - w) / 2
val radius = min(w, h) / 2f
outline.setRoundRect(
view.paddingLeft + offsetHorizontal,
view.paddingTop + offsetVertical,
view.width - view.paddingRight - offsetHorizontal,
view.height - view.paddingBottom - offsetVertical,
radius
)
}
}
需要注意的是,ViewOutlineProvider 不能在 API 21(Android 5.0)以下使用。