目錄

前言
之前做了一個(gè)答題的小游戲,有一個(gè)倒計(jì)時(shí)的效果,因此就寫(xiě)了一個(gè),在此記錄一下方便以后使用
實(shí)現(xiàn)效果

實(shí)現(xiàn)原理
1.首先畫(huà)一個(gè)白色的圓作為背景,然后利用Paint的setShadowLayer方法為圓形背景加一個(gè)投影,使其更有立體感。

2.利用Canvas的drawArc方法在這個(gè)圓的上方畫(huà)一個(gè)圓環(huán),這里需要將Paint的Style設(shè)置為Paint.Style.STROKE

3.用Canvas的drawText方法將倒計(jì)時(shí)的時(shí)間畫(huà)到控件中心位置

4.最后創(chuàng)建一個(gè)ValueAnimator用來(lái)改變圓弧的長(zhǎng)度和倒計(jì)時(shí)的數(shù)字,從而產(chǎn)生動(dòng)畫(huà)效果。
代碼展示
/**
* 倒計(jì)時(shí)控件
*/
class TimeDownView: View {
private var mPaintRing: Paint = Paint(Paint.ANTI_ALIAS_FLAG) //環(huán)形的圓的畫(huà)筆
private var mPaintCircle:Paint = Paint(Paint.ANTI_ALIAS_FLAG)//圓形背景的畫(huà)筆
private var mPaintTimeText = Paint(Paint.ANTI_ALIAS_FLAG) //時(shí)間文字的畫(huà)筆
private var mShadowSize = 10f//陰影大小
private var mRingWidth = 20f//圓環(huán)寬度
private var mAnimator: ValueAnimator? = null
private var mRectfRing: RectF? = null //圓環(huán)的矩形
private var mProgress = 10f //進(jìn)度
private var mAngle = 90F
private var mTextBaseY = 0F//文字居中的位置
var mTimeCountDownCallBack:TimeCountDownCallBack? = null
constructor(context: Context) : super(context){
init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
{
init()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
init()
}
private fun init(){
setLayerType(LAYER_TYPE_SOFTWARE,null)//關(guān)閉硬件加速
mPaintCircle.color = Color.WHITE
mPaintCircle.style = Paint.Style.FILL
mPaintCircle.setShadowLayer(mShadowSize,0F,0F,Color.BLACK)
mPaintRing.color = Color.BLUE
mPaintRing.style = Paint.Style.STROKE
mPaintRing.strokeWidth = mRingWidth
mPaintTimeText.color = Color.BLACK
mPaintTimeText.textAlign = Paint.Align.CENTER
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mRingWidth = width / 10F
mPaintTimeText.strokeWidth = mRingWidth
mPaintTimeText.textSize = (width - mShadowSize - mRingWidth)/2
val ringMargen = mRingWidth/3*2
mRectfRing = RectF(ringMargen+mShadowSize,ringMargen+mShadowSize,width-ringMargen-mShadowSize,height-ringMargen-mShadowSize)
val fontMetrics = mPaintTimeText.fontMetrics
// 計(jì)算文字高度
val fontHeight = fontMetrics.bottom - fontMetrics.top
// 計(jì)算文字baseline 讓文字垂直居中
mTextBaseY = height - (height - fontHeight) / 2 - fontMetrics.bottom
startAnim()
}
/**
* 開(kāi)始動(dòng)畫(huà)
*/
fun startAnim(){
if(mAnimator!=null){
mAnimator!!.cancel()
}
mAnimator = ValueAnimator.ofFloat(11f, 1f)
mAnimator!!.duration = 10000L
//設(shè)置動(dòng)畫(huà)差值器,讓動(dòng)畫(huà)為勻速動(dòng)畫(huà)
mAnimator!!.interpolator = LinearInterpolator()
mAnimator!!.addUpdateListener {
mProgress = it.animatedValue as Float
invalidate()
}
mAnimator!!.repeatMode = ValueAnimator.RESTART
mAnimator!!.repeatCount = ValueAnimator.INFINITE
mAnimator!!.addListener(object : AnimatorListenerAdapter(){
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
}
override fun onAnimationRepeat(animation: Animator?) {
super.onAnimationRepeat(animation)
//回調(diào)倒計(jì)時(shí)重復(fù)的事件
if(mTimeCountDownCallBack!=null){
mTimeCountDownCallBack!!.onRepeat()
}
}
})
mAnimator!!.start()
}
/**
* 結(jié)束動(dòng)畫(huà)
*/
fun stopAnim(){
if(mAnimator!=null){
mAnimator!!.cancel()
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
mAnimator?.cancel()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val centerX:Float = (width / 2).toFloat()
val centerY:Float = (height / 2).toFloat()
// 畫(huà)圓形背景
canvas!!.drawCircle(centerX,centerY,Math.min(centerX,centerY)-mShadowSize,mPaintCircle)
//畫(huà)圓環(huán)
canvas.drawArc(mRectfRing!!,0F - mAngle,-36F*(mProgress-1),false,mPaintRing)
canvas.drawText("${mProgress.toInt()}",centerX,mTextBaseY,mPaintTimeText)
}
/**
* 倒計(jì)時(shí)結(jié)束的時(shí)候的回調(diào)
*/
interface TimeCountDownCallBack{
fun onRepeat()
}
}