
android.gif
class CreditMeter @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val _color_progress_bg = Color.parseColor("#f0f0f0") //进度背景
private val _color_grade_excellent = Color.parseColor("#0084FF") //主颜色
private val _color_grade = Color.parseColor("#999999")
private val _color_fraction = Color.parseColor("#333333")
private val _color_pointer = _color_grade_excellent //指针颜色
private val maxFraction = 100f //最大分数
private val maxAngle = 270f //进度条划过最大角度
private val progressWidth = 40f
private val pointerWidth = 6f //指针宽度
private var scaleSpinAngle = 50f //刻度标记市相对于中间刻度的角度
private var currentAnimationProgress = 0f //当前动画执行进度
set(value) {
field = value
postInvalidate()
}
private var currentFraction: Int = 0 //当前信用等级分数
set(value) {
field = value
postInvalidate()
}
private val currentFractionGradeValue: String //当前分数对应等级
get() {
return when {
currentFraction < 60 -> {
"信用差"
}
currentFraction < 80 -> {
"信用中等"
}
currentFraction < 90 -> {
"信用良好"
}
else -> {
"信用优秀"
}
}
}
private val progressPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val textPaint = TextPaint(progressPaint)
private val paintPointer = Paint(progressPaint)
private val oval = RectF() //绘制范围
init {
progressPaint.style = Paint.Style.STROKE
progressPaint.strokeWidth = progressWidth
//指针画笔
paintPointer.style = Paint.Style.STROKE
paintPointer.color = _color_pointer
paintPointer.strokeWidth = pointerWidth
//文字画笔
textPaint.color = _color_fraction
textPaint.textAlign = Paint.Align.CENTER
textPaint.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val widthModel = MeasureSpec.getMode(widthMeasureSpec)
var widthSize = MeasureSpec.getSize(widthMeasureSpec)
var heightSize = MeasureSpec.getSize(heightMeasureSpec)
when (widthModel) {
MeasureSpec.UNSPECIFIED -> { //不限制
widthSize = 200
}
MeasureSpec.AT_MOST -> { //最大只能 Match
}
MeasureSpec.EXACTLY -> { //指定
}
}
if (widthSize < heightSize) {
heightSize = widthSize
} else {
widthSize = heightSize
}
setMeasuredDimension(widthSize, heightSize)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas ?: return
//绘制背景圆弧
drawBackground(canvas)
//绘制刻度
drawCalibration(canvas)
//绘制等级文字
relDrawCalibrationContent(canvas)
//绘制进度条
drawProgress(canvas)
//绘制当前分数
drawGradeAndFraction(canvas)
//绘制中心圆和指针
drawPointer(canvas)
}
/**
* 绘制背景圆弧
*/
private fun drawBackground(canvas: Canvas) {
progressPaint.style = Paint.Style.STROKE
progressPaint.strokeWidth = progressWidth
progressPaint.color = _color_progress_bg
oval.set(
progressPaint.strokeWidth / 2,
progressPaint.strokeWidth / 2,
measuredWidth.toFloat() - progressPaint.strokeWidth / 2,
measuredHeight.toFloat() - progressPaint.strokeWidth / 2
)
canvas.drawArc(oval, 135f, maxAngle, false, progressPaint)
}
/**
* 绘制刻度等级区分
* 中间刻度线 270度
* 旋转-50
* 旋转+1000
* 旋转-50
* 绘制文字
*/
private fun drawCalibration(canvas: Canvas) {
progressPaint.style = Paint.Style.FILL_AND_STROKE
progressPaint.color = _color_grade_excellent
progressPaint.strokeWidth = 4f
relDrawCalibration(canvas)
canvas.rotate(-scaleSpinAngle, (width / 2).toFloat(), (height / 2).toFloat())
relDrawCalibration(canvas)
canvas.rotate(scaleSpinAngle * 2, (width / 2).toFloat(), (height / 2).toFloat())
relDrawCalibration(canvas)
canvas.rotate(-scaleSpinAngle, (width / 2).toFloat(), (height / 2).toFloat())
}
/**
* 绘制刻度
* 角度区间为50度
*/
private fun relDrawCalibration(canvas: Canvas) {
paintPointer.strokeWidth = 6f
canvas.drawLine(
(measuredWidth / 2).toFloat(),
progressWidth + 4f,
(measuredWidth / 2).toFloat(),
progressWidth + 30f, paintPointer
)
}
/**
* 绘制刻度文字提示
*/
private fun relDrawCalibrationContent(canvas: Canvas) {
textPaint.textSize = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 12f,
resources.displayMetrics
)
textPaint.color = _color_grade
getPointerFromAngleAndRadius(
(maxAngle - scaleSpinAngle / 2).toInt(),
(width / 2 - progressWidth * 2.5).toInt()
).apply {
canvas.drawText("中", this[0], this[1], textPaint)
}
getPointerFromAngleAndRadius(
(maxAngle - scaleSpinAngle * 1.5).toInt(),
(width / 2 - progressWidth * 2.5).toInt()
).apply {
canvas.drawText("差", this[0], this[1], textPaint)
}
getPointerFromAngleAndRadius(
(maxAngle + scaleSpinAngle / 2).toInt(),
(width / 2 - progressWidth * 2.5).toInt()
).apply {
canvas.drawText("良", this[0], this[1], textPaint)
}
getPointerFromAngleAndRadius(
(maxAngle + scaleSpinAngle * 1.5).toInt(),
(width / 2 - progressWidth * 2.5).toInt()
).apply {
canvas.drawText("优", this[0], this[1], textPaint)
}
}
/**
* 绘制信用等级以及分数
*/
private fun drawGradeAndFraction(canvas: Canvas) {
textPaint.textSize = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 17f,
resources.displayMetrics
)
textPaint.color = _color_fraction
val fontMetrics = textPaint.fontMetrics
val textHeight = fontMetrics.bottom - fontMetrics.top
//绘制信用分数
canvas.drawText(
"$currentFraction",
(width / 2).toFloat(),
height - progressWidth,
textPaint
)
textPaint.textSize = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 12f,
resources.displayMetrics
)
textPaint.color = _color_grade
//信用等级
canvas.drawText(
currentFractionGradeValue,
(width / 2).toFloat(),
height - textHeight - progressWidth,
textPaint
)
}
/**
* 需要动画
* 需要指针
*/
private fun drawProgress(canvas: Canvas) {
//绘制当前进度
/**************以下为绘制进度***************/
progressPaint.style = Paint.Style.STROKE
progressPaint.color = _color_grade_excellent
progressPaint.strokeWidth = progressWidth
canvas.drawArc(oval, 135f, currentAnimationProgress, false, progressPaint)
}
/**
* 绘制指针
*/
private val pointerPath = Path()
private fun drawPointer(canvas: Canvas) {
//绘制中心指针圆
canvas.drawCircle(
(measuredWidth / 2).toFloat(),
(measuredHeight / 2).toFloat(),
16f,
paintPointer
)
val angle = currentAnimationProgress + 135f //当前指针的角度
val currentPointerPoint = getPointerFromAngleAndRadius(angle.toInt(), width / 4)
val centerCirclePoint = getPointerFromAngleAndRadius(angle.toInt(), 16)
pointerPath.moveTo(centerCirclePoint[0], centerCirclePoint[1])
pointerPath.lineTo(currentPointerPoint[0], currentPointerPoint[1])
pointerPath.close()
canvas.drawPath(pointerPath, paintPointer)
pointerPath.reset()
}
/**
* 得到当前指针
* 在当前角度下 当前半径下的 外切圆点
*/
private fun getPointerFromAngleAndRadius(angle: Int, radius: Int): FloatArray {
val x = radius * cos(angle * Math.PI / 180) + width / 2
val y = radius * sin(angle * Math.PI / 180) + height / 2
return floatArrayOf(x.toFloat(), y.toFloat())
}
/**
* 进度动画
* 指针动画
*/
fun startAnimation(targetProgress: Int) {
val progress: Float
val scale = targetProgress / maxFraction
when {
scale < 0.6 -> {
//当前的进度配分为格格
progress = ((maxAngle / 2 - scaleSpinAngle) / 60) * targetProgress
}
scale < 0.8 -> {
progress =
(maxAngle / 2 - scaleSpinAngle) + (scaleSpinAngle / 20) * (targetProgress - 60)
}
scale < 0.9 -> {
progress = maxAngle / 2 + (scaleSpinAngle / 10) * (targetProgress - 80)
}
else -> {
val scaleAngle90 = maxAngle / 2 + scaleSpinAngle //90分刻度的扫过角度
progress = scaleAngle90 + ((maxAngle - scaleAngle90) / 60) * (targetProgress - 90)
}
}
val fractionAni = ObjectAnimator.ofInt(this, "currentFraction", 0, targetProgress)
val progressAni = ObjectAnimator.ofFloat(this, "currentAnimationProgress", 0f, progress)
AnimatorSet().apply {
playTogether(progressAni, fractionAni)
duration = 500
interpolator = AccelerateDecelerateInterpolator()
start()
}
}
}
网友评论