Android實(shí)現(xiàn)答題倒計(jì)時(shí)效果

目錄

前言

之前做了一個(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()
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容