最近突然要用到带有进度的下载按钮,暂时找不到满意的轮子,自己动手丰衣足食。
两个主要特性:
- 文字反色
- 按钮镂空透明
文字的反色处理,有两种方案。
一种是使用两层布局,两层布局分别使用反色来处理,再通过clipPath切割上层布局,切割掉的部分漏出下层的反色布局,以此来实现进度反色的效果。
第二种则是使用canvas绘图,通过xfermode叠加绘制来实现镂空效果。
这里使用第二种方案,原因如下:
1.布局叠加无法实现反色部分透明,无法看到按钮下的布局。
2.太low
实现文字反色比较简单,通过XOR类型的文字paint叠加绘制到底层button上就可以了。
paintTxt.xfermode = PorterDuffXfermode(PorterDuff.Mode.XOR)
注意要先绘button,再绘text。
当然本篇的核心并不在如何使用canvas来绘制控件,而是如何绘制出底部透明镂空的view,恩,奇技淫巧.
首先看一下这个button的特性:
1.文字反色
2.镂空的部位透明
3.边框
4.圆角
5.进度
这里的圆角和透明是个关键,设计的时候卡在了这里好久。
绘制步骤分为4个
需要定义四个paint分别对应四次绘制
paint的定义放在构造方法中,绘制在onDraw方法中
reactF是组件将要绘制的矩形区域,在onMeasure中测量得到。
maskReacF是组件第二部裁剪绘制的矩形区域,左边界根据进度控制,上右下和组件边界相同。
一、绘制中心颜色
paint定义
paintBg.color = color
paintBg.isAntiAlias = true
绘制
canvas.drawRoundRect(rectF, radius, radius, paintBg)
二、根据进度裁剪中心颜色
paint定义
paintFront.color = color
paintFront.isAntiAlias = true
paintFront.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
绘制
maskRectF.left = rectF.left + progress * (rectF.right - rectF.left)
canvas.drawRect(maskRectF, paintFront)
三、绘制边框
paint定义
paintBorder.color = color
paintBorder.isAntiAlias = true
paintBorder.strokeWidth = borderWidth
paintBorder.style = Paint.Style.STROKE
绘制
canvas.drawRoundRect(rectF, radius, radius, paintBorder)
四、绘制文字
paint定义
paintTxt.color = color
paintTxt.textSize = textSize
paintTxt.isAntiAlias = true
paintTxt.xfermode = PorterDuffXfermode(PorterDuff.Mode.XOR)
paintTxt.textAlign = Paint.Align.LEFT
绘制
val text = "暂停"
paintTxt.getTextBounds(text, 0, text.length, txtRect)
val textX = (viewWidth / 2) - txtRect.centerX()
val textY = (viewHeight / 2) - txtRect.centerY()
canvas.drawText(text, textX.toFloat(), textY.toFloat(), paintTxt)
搞定。
接下来把一些参数(尺寸,颜色,边框,圆角,状态,进度等)进行封装,留出接口供业务调用即可,这里不再赘述。