android 圆形进度狂,android 圆形进度条

这个博客介绍了如何创建一个自定义的圆形进度条控件,包括更新和暂停状态的显示,以及颜色和样式的设置。通过使用Paint、Scroller、Path等Android图形库,实现了播放和暂停图标的变化,并提供了监听状态改变的功能。
摘要由CSDN通过智能技术生成

圆形的进度条,自定义控件实现

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)

//获取进度条宽度

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) {

//相对parent的坐标

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

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值