持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
该问题拆解为:自定义View -> 实现正方形效果 -> 切割为圆形 -> 描边
1、自定义CircleImageView继承AppCompatImageView
View有三个构造函数,在创建时不需要全部继承父类的构造函数。只需要继承带三个参数的构造函数,其他两个构造函数链式调用这个构造函数。在进行初始化时,只需要在这个构造函数内初始化即可。
class CircleImageView : AppCompatImageView {
constructor(context: Context) : this(context, null)
constructor(context: Context, attributes: AttributeSet?) : this(context, attributes, 0)
constructor(context: Context, attributes: AttributeSet?, defStyleAttr: Int) : super(context,attributes, defStyleAttr)
}
2、正方形的实现
重写View测量方法onMeasure(),设置ImageView的长、宽为测量宽度,实现正方形ImageView。
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
setMeasuredDimension(measuredWidth, measuredWidth)
}
3、圆形的实现
重写View绘制方法onDraw(),通过路径将画布裁剪成圆形。这是最便捷的方法,但是处理出来的圆形会有锯齿,只适合小图片。
class CircleImageView : AppCompatImageView {
private val path: Path = Path()
override fun onDraw(canvas: Canvas?) {
canvas?.save()
path.reset()
path.addCircle(width / 2f, height / 2f, width / 2f, Path.Direction.CCW)
canvas?.clipPath(path)
super.onDraw(canvas)
canvas?.restore()
}
......
}
4、描边的实现
描边有颜色和宽度两个属性,需要对这两个属性进行定义。
在资源文件中声明这两个自定义属性,注意属性的类型是尺寸和颜色值。
<resources>
<declare-styleable name="CircleImageView">
<attr name="borderWidth" format="dimension" />
<attr name="borderColor" format="color" />
</declare-styleable>
</resources>
在构造方法中对这两个属性进行获取,注意先判断是否有这两个属性值,如果没有赋默认值。在borderCorlor的set方法中调用invalidate(),可以实现动态设置描边颜色。
class CircleImageView : AppCompatImageView {
private var borderWidth: Float
var borderCorlor: Int
set(value) {
field=value
invalidate()
}
constructor(context: Context, attributes: AttributeSet?, defStyleAttr: Int) : super(
context,
attributes,
defStyleAttr
) {
val typeArray = context.obtainStyledAttributes(
attributes,
R.styleable.CircleImageView,
defStyleAttr,
defStyleAttr
)
borderWidth =
if (typeArray.hasValue(R.styleable.CircleImageView_borderWidth)) {
typeArray.getDimension(R.styleable.CircleImageView_borderWidth, 0f)
} else {
0f
}
borderCorlor = if (typeArray.hasValue(R.styleable.CircleImageView_borderColor)) {
typeArray.getColor(
R.styleable.CircleImageView_borderColor,
resources.getColor(R.color.transparent)
)
} else {
resources.getColor(R.color.transparent)
}
}
......
}
接着构建画笔,在绘制完图片之后进行描边
class CircleImageView : AppCompatImageView {
private val path: Path = Path()
private val borderPaint: Paint = Paint()
override fun onDraw(canvas: Canvas?) {
//裁剪
canvas?.save()
path.reset()
path.addCircle(width / 2f, height / 2f, width / 2f, Path.Direction.CCW)
canvas?.clipPath(path)
super.onDraw(canvas)
//描边
borderPaint.setColor(borderCorlor)
borderPaint.isAntiAlias = true
borderPaint.style = Paint.Style.STROKE
borderPaint.strokeWidth = borderWidth
canvas?.drawCircle(width / 2f, height / 2f, width / 2f, borderPaint)
canvas?.restore()
}
}
以下是效果图,上面是带描边的效果,下面的图是没有描边的。当图片较大时锯齿会很明显。