android 圓形進(jìn)度條

圓形的進(jìn)度條踪旷,自定義控件實(shí)現(xiàn)

package reed.flyingreed.widget

import android.content.Context
import android.graphics.*
import android.support.annotation.ColorInt
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout

import android.widget.Scroller

import reed.flyingreed.R
import kotlinx.android.synthetic.main.control_play_pause.view.*

/**
 * Created by thinkreed on 2017/6/28.
 */
class PlayPauseProgress(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) {

    private val mProgressPaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG)
    }

    private val mCirclePaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG)
    }

    private var mStrokeWidth = 0f

    private lateinit var mScroller: Scroller
    private val mRectF by lazy { RectF() }
    private var mState = State.UPDATING
    private var mSweeppedAngle = 0f
    private lateinit var mPlayImage: View
    private lateinit var mContext: Context
    private lateinit var mOnStateChangeListener: OnStateChangeListener
    private val mLeftTopPoint by lazy {
        PointF()
    }
    private val mLeftBottomPoint by lazy {
        PointF()
    }
    private val mRightTopPoint by lazy {
        PointF()
    }
    private val mRightBottomPoint by lazy {
        PointF()
    }
    private val mRightCenterPoint by lazy {
        PointF()
    }
    private val mPath by lazy { Path() }
    private var mColor = 0

    init {
        if (!isInEditMode) {
            //允許繪制
            setWillNotDraw(false)
            //加載布局
            LayoutInflater.from(context).inflate(R.layout.control_play_pause, this, true)
            mPlayImage = center_image
            mPlayImage.setOnClickListener {
                when (mState) {
                    State.UPDATING -> {
                        mState = State.IDLE
                        mProgressPaint.color = resources.getColor(R.color.colorWhite)
                    }
                    State.IDLE -> {
                        mState = State.UPDATING
                        mProgressPaint.color = resources.getColor(mColor)
                    }
                    else -> return@setOnClickListener
                }
                postInvalidate()
                mOnStateChangeListener.onStateChanged(mState)
            }
            //獲取xml中定義的屬性
            val a = context.theme.obtainStyledAttributes(attrs, R.styleable.PlayPauseProgress, 0, 0)
            //獲取進(jìn)度條寬度
            mStrokeWidth = a.getDimension(R.styleable.PlayPauseProgress_stroke_width, 0f)
            mProgressPaint.color = resources.getColor(android.R.color.transparent)
            mProgressPaint.strokeWidth = mStrokeWidth
            mProgressPaint.style = Paint.Style.STROKE
            mCirclePaint.color = resources.getColor(R.color.colorLightGray)
            mCirclePaint.style = Paint.Style.STROKE
            mCirclePaint.strokeWidth = mStrokeWidth
            mContext = context
            mScroller = Scroller(context, null, true)
            a.recycle()
        }

    }

    override fun onDraw(canvas: Canvas?) {
        canvas?.let {
            //繪制已走完的弧線
            canvas.drawArc(mRectF, 270f + mSweeppedAngle,
                    360f - mSweeppedAngle, false, mCirclePaint)
            //繪制未走完的弧線
            canvas.drawArc(mRectF, 270f, mSweeppedAngle, false, mProgressPaint)
            when (mState) {
                State.UPDATING -> {
                    //繪制暫停
                    canvas.drawLine(mLeftTopPoint.x, mLeftTopPoint.y, mLeftBottomPoint.x,
                            mLeftBottomPoint.y, mProgressPaint)
                    canvas.drawLine(mRightTopPoint.x, mRightTopPoint.y, mRightBottomPoint.x,
                            mRightBottomPoint.y, mProgressPaint)
                }
                State.IDLE -> {
                    //繪制播放按鈕
                    mPath.moveTo(mLeftTopPoint.x, mLeftTopPoint.y)
                    mPath.lineTo(mLeftBottomPoint.x, mLeftBottomPoint.y)
                    mPath.lineTo(mRightCenterPoint.x, mRightCenterPoint.y)
                    mPath.lineTo(mLeftTopPoint.x, mLeftTopPoint.y)
                    canvas.drawPath(mPath, mProgressPaint)
                }
                else -> return
            }
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val w = MeasureSpec.getSize(widthMeasureSpec)
        val h = MeasureSpec.getSize(heightMeasureSpec)
        val r = if (w > h) h / 4 else w / 4
        for (i in 0 until childCount) {
            getChildAt(i).measure(ViewGroup.getChildMeasureSpec(widthMeasureSpec, 0, r),
                    ViewGroup.getChildMeasureSpec(heightMeasureSpec, 0, r))
        }
        setMeasuredDimension(2 * r, 2 * r)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        //相對(duì)parent的坐標(biāo)
        mRectF.left = mStrokeWidth
        mRectF.right = right - left - mStrokeWidth
        mRectF.top = mStrokeWidth
        mRectF.bottom = bottom - top - mStrokeWidth

        for (i in 0 until childCount) {
            val child = getChildAt(i)
            val width = child.measuredWidth
            val height = child.measuredHeight
            val cl = (right - left - width) / 2
            val ct = (bottom - top - height) / 2
            val cc = (bottom - top) / 2
            val sqrt3 = Math.sqrt(3.0)
            //等邊三角形的播放按鈕婉称,邊長為2 * sqrt(3) * width /4
            mLeftTopPoint.x = (cl + width / 4).toFloat()
            mLeftTopPoint.y = (cc - width / 4 * sqrt3).toFloat()
            mLeftBottomPoint.x = (cl + width / 4).toFloat()
            mLeftBottomPoint.y = (cc + width / 4 * sqrt3).toFloat()
            mRightTopPoint.x = (cl + width / 4 * 3).toFloat()
            mRightTopPoint.y = (cc - width / 4 * sqrt3).toFloat()
            mRightCenterPoint.x = (cl + width).toFloat()
            mRightCenterPoint.y = cc.toFloat()
            mRightBottomPoint.x = (cl + width / 4 * 3).toFloat()
            mRightBottomPoint.y = (cc + width / 4 * sqrt3).toFloat()
            child.layout(cl, ct, cl + width, ct + height)
        }
    }

    override fun onDetachedFromWindow() {
        mState = State.IDLE
        super.onDetachedFromWindow()
    }

    fun setProgress(progress: Float) {
        if (progress == mSweeppedAngle / 360f) {
            mState = State.IDLE
        }
        mSweeppedAngle = progress * 360f
        mState = State.UPDATING
        postInvalidate()
    }

    fun setOnStateChangeListener(listener: OnStateChangeListener) {
        mOnStateChangeListener = listener
    }

    fun setThemeColor(color: Int) {
        mColor = color
        mProgressPaint.color = resources.getColor(mColor)
    }

    enum class State {
        UPDATING, IDLE
    }

    interface OnStateChangeListener {
        fun onStateChanged(state: State): Unit
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末调塌,一起剝皮案震驚了整個(gè)濱河市扶檐,隨后出現(xiàn)的幾起案子诚欠,更是在濱河造成了極大的恐慌紫皇,老刑警劉巖空另,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盆耽,死亡現(xiàn)場離奇詭異,居然都是意外死亡扼菠,警方通過查閱死者的電腦和手機(jī)摄杂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來循榆,“玉大人析恢,你說我怎么就攤上這事⊙硪” “怎么了映挂?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盗尸。 經(jīng)常有香客問我柑船,道長,這世上最難降的妖魔是什么振劳? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任椎组,我火速辦了婚禮油狂,結(jié)果婚禮上历恐,老公的妹妹穿的比我還像新娘。我一直安慰自己专筷,他們只是感情好弱贼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著磷蛹,像睡著了一般吮旅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天庇勃,我揣著相機(jī)與錄音檬嘀,去河邊找鬼。 笑死责嚷,一個(gè)胖子當(dāng)著我的面吹牛鸳兽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播罕拂,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼揍异,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了爆班?” 一聲冷哼從身側(cè)響起衷掷,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柿菩,沒想到半個(gè)月后戚嗅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枢舶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年渡处,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祟辟。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡医瘫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旧困,到底是詐尸還是另有隱情醇份,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布吼具,位于F島的核電站僚纷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拗盒。R本人自食惡果不足惜怖竭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望陡蝇。 院中可真熱鬧痊臭,春花似錦、人聲如沸登夫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恼策。三九已至鸦致,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背分唾。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工抗碰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绽乔。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓改含,卻偏偏與公主長得像,于是被迫代替她去往敵國和親迄汛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捍壤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容