大家好,最近项目中遇到了一个空调调节开关,感觉对于新手还是有点难度的,话不多说,先来看看具体的样式。
class AirConditionerView : View {
private var mSize = 0f
private lateinit var mRectF: RectF
private val widthBgCircle = 50f
private val widthCircle = 20f
private val startTemp = 16
private val endTemp = 30
private var currentTemp = 20
private var oldTemp = 0
private var oldLength = 0f
private var totalLength = 0f
private var unitLength = 0f
private var isAdd = true
private var mAnimator : ValueAnimator? = null
private val SWEEP_GRADIENT_COLORS =
intArrayOf(Color.parseColor("#FF00B6BB"), Color.parseColor("#FFFFAD40"),Color.RED)
private lateinit var mRingPath: Path
private lateinit var mRingPathBg: Path
private lateinit var mDstPath: Path
private lateinit var mPaintBg: Paint
private lateinit var mPaint: Paint
private lateinit var mPathMeasure: PathMeasure
private var mCurAnimValue by Delegates.notNull<Float>()
private var linearGradient: SweepGradient? = null
constructor(context: Context) : super(context) {
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
setLayerType(LAYER_TYPE_SOFTWARE, null)
//画笔
mPaintBg = Paint(Paint.ANTI_ALIAS_FLAG)
mPaintBg.style = Paint.Style.STROKE
mPaintBg.strokeWidth = widthBgCircle
mPaintBg.color = Color.WHITE
mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mPaint.style = Paint.Style.STROKE
mPaint.strokeCap = Paint.Cap.ROUND
mPaint.strokeWidth = widthCircle
//路径
mRingPathBg = Path()
mRingPath = Path()
mDstPath = Path()
startAnimator()
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mSize = min(w, h).toFloat()
mRectF = RectF(
widthBgCircle / 2,
widthBgCircle / 2,
mSize - widthBgCircle / 2,
mSize - widthBgCircle / 2
)
mPaint.shader = getSweepGradient()
//背景白色圆环添加尺寸
mRingPathBg.reset()
mRingPathBg.addArc(mRectF, 0f, 360f)
//温度圆环路径
mRingPath.reset()
mRingPath.addArc(mRectF, 60f, 240f)
mPathMeasure = PathMeasure(mRingPath, false)
//计算每度的单位长度
totalLength = mPathMeasure.length
unitLength = totalLength / (endTemp - startTemp)
oldLength = (currentTemp - startTemp) * unitLength
oldTemp = currentTemp
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
mPaintBg.style = Paint.Style.FILL
mPaintBg.textSize=50f
mPaintBg.textAlign = Paint.Align.CENTER
//绘制中间的温度
val fontMetrics: Paint.FontMetrics = mPaintBg.fontMetrics
val fontHeight: Float = fontMetrics.bottom - fontMetrics.top
val textBaseY: Float = height - (height - fontHeight) / 2 - fontMetrics.bottom
canvas?.drawText("$currentTemp°C",mSize/2,textBaseY,mPaintBg)
//绘制两边的温度
mPaintBg.textSize = 20f
canvas?.drawText("${startTemp}°C",20f,mSize-20,mPaintBg)
canvas?.drawText("${endTemp}°C",mSize-20,mSize-20,mPaintBg)
canvas?.rotate(90f, mSize / 2, mSize / 2)
//画背景白色圆环
mPaintBg.strokeWidth = widthBgCircle
mPaintBg.style = Paint.Style.STROKE
canvas?.drawPath(mRingPathBg, mPaintBg)
mDstPath.reset()
var currentLength = 0f
if (isAdd){
currentLength = oldLength + unitLength * (currentTemp - oldTemp) * mCurAnimValue
mPathMeasure.getSegment(0f, currentLength, mDstPath, true)
canvas?.drawPath(mDstPath, mPaint)
}else{
currentLength = oldLength - unitLength *(oldTemp - currentTemp) * mCurAnimValue
mPathMeasure.getSegment(0f, currentLength, mDstPath, true)
canvas?.drawPath(mDstPath, mPaint)
}
if (mCurAnimValue == 1f){
oldLength = currentLength
oldTemp = currentTemp
}
}
private fun startAnimator() {
mAnimator?.cancel()
mAnimator = ValueAnimator.ofFloat(0f, 1f)
mAnimator?.addUpdateListener {
mCurAnimValue = mAnimator?.animatedValue as Float
invalidate()
}
mAnimator?.duration = 150
mAnimator?.start()
mAnimator?.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator?) {
}
override fun onAnimationEnd(animation: Animator?) {
}
override fun onAnimationCancel(animation: Animator?) {
}
override fun onAnimationRepeat(animation: Animator?) {
}
})
}
/**
* 获取线性渐变
*
* @return
*/
private fun getSweepGradient(): SweepGradient? {
if (linearGradient == null) {
linearGradient = SweepGradient(
mSize / 2,
mSize / 2,
SWEEP_GRADIENT_COLORS,
null
)
}
return linearGradient
}
fun addTemp() {
if (mAnimator?.isRunning == true){
return
}
Log.e("wzy","$currentTemp")
if (currentTemp>=endTemp){
ToastUtil.show("温度已经最高")
return
}
currentTemp++
isAdd = true
startAnimator()
}
fun reduceTemp() {
if (mAnimator?.isRunning == true){
return
}
Log.e("wzy","$currentTemp")
if (currentTemp<=startTemp){
ToastUtil.show("温度已经最低")
return
}
isAdd = false
currentTemp--
startAnimator()
}
}
然后直接放入布局文件
<....AirConditionerView
android:id="@+id/airConditionerView"
android:layout_width="200dp"
android:layout_height="200dp"/>
然后在activity中调用即可
airConditionerView.reduceTemp()
airConditionerView.addTemp()
搞定了。。。easy