android|一个简单的Android圆形ProgressBar

使用kotlin实现一个简单的Android圆形ProgressBar 【android|一个简单的Android圆形ProgressBar】本自定义View功能比较简单,就是一个包含百分比的圆形进度条,先上结果图(新手,大神勿喷)
android|一个简单的Android圆形ProgressBar
文章图片

代码如下所示,支持padding设置,背景线条颜色设置

"backgroundColor" format="color" /> "textColor" format="color" /> "arcWidth" format="integer" /> //CircleProgressBar.kt package com.hefuwei.progressviewimport android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Rect import android.os.Build import android.support.annotation.RequiresApi import android.util.AttributeSet import android.view.View/** * Created by hefuwei on 2018/3/29. */ class CircleProgressBar(context:Context,set:AttributeSet?): View(context,set){private val paint:Paint = Paint(Paint.ANTI_ALIAS_FLAG) //设置抗锯齿 private val smallestSize:Int = 150 //当设置为wrap_content时的最小尺寸 private var progress:Int = 0 private val arcWidth:Int //进度条外边缘线 private val boundRect = Rect()init { val typeArray = context.obtainStyledAttributes(set,R.styleable.CircleProgressBar) setBackgroundColor(typeArray.getColor(R.styleable.CircleProgressBar_backgroundColor,Color.BLACK)) //获取xml定义的backgroundColor并设置 paint.color = typeArray.getColor(R.styleable.CircleProgressBar_textColor,Color.WHITE) arcWidth = typeArray.getInt(R.styleable.CircleProgressBar_arcWidth,3) paint.strokeWidth = arcWidth.toFloat() typeArray.recycle() //回收typeArray 防止内存泄露 }constructor(context: Context):this(context, null) //次构造器@RequiresApi(Build.VERSION_CODES.LOLLIPOP) //偷个懒不用RectF override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) val width = measuredWidth - paddingLeft - paddingRight //获取实际可用于绘制的宽高 val height = measuredHeight - paddingBottom - paddingTop if(canvas != null){ paint.style = Paint.Style.FILL //使用填充模式画文字 if(progress >= 10){ drawText("$progress%",canvas) }else{ drawText("0$progress%",canvas) } paint.color = Color.RED paint.style = Paint.Style.STROKE //使用画线模式画圆弧 if(height > width){ //计算圆弧位置 以最小边的一半为半径 canvas.drawArc(paddingLeft.toFloat()+arcWidth/2, (height-width+arcWidth)/2.toFloat(), measuredWidth.toFloat()-arcWidth/2-paddingRight, (height+width+arcWidth)/2.toFloat(), 135f,2.7f*progress.toFloat(),false,paint) } else { canvas.drawArc((width-height)/2.toFloat(), paddingTop.toFloat()+arcWidth/2, (width+height)/2.toFloat(), measuredHeight.toFloat()-arcWidth/2-paddingBottom, 135f,2.7f*progress.toFloat(),false,paint) } } }private fun drawText(str:String, canvas:Canvas){ paint.getTextBounds(str,0,str.length,boundRect) //注意drawText的起点是位于第一个字的左下 canvas.drawText(str,(measuredWidth-boundRect.right+boundRect.left+paddingLeft-paddingRight)/2.toFloat() ,(measuredHeight+boundRect.bottom-boundRect.top-paddingTop-paddingBottom)/2.toFloat(),paint) }override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) val widthSize = MeasureSpec.getSize(widthMeasureSpec) val widthMode = MeasureSpec.getMode(widthMeasureSpec) val heightSize = MeasureSpec.getSize(heightMeasureSpec) val heightMode = MeasureSpec.getMode(heightMeasureSpec) if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){ //解决wrap_content与match_content效果一致的问题 setMeasuredDimension(smallestSize,smallestSize) }else if(widthMode == MeasureSpec.AT_MOST){ setMeasuredDimension(smallestSize,heightSize) }else if(heightMode == MeasureSpec.AT_MOST){ setMeasuredDimension(widthSize,smallestSize) } chooseRightTextSize() //选择合适的textSize避免text比外面的框大 }private fun chooseRightTextSize(){ var lastSize = 1 for(i in 1..500){ paint.textSize = i.toFloat() paint.getTextBounds("100%",0,"100%".length,boundRect) if((boundRect.right - boundRect.left)*1.9 < measuredWidth-paddingLeft-paddingRight && (boundRect.bottom - boundRect.top)*4 < measuredHeight-paddingTop-paddingBottom){ lastSize = i }else{ paint.textSize = lastSize.toFloat() return } } }fun setProgress(progress:Int){ when { progress < 0 -> this.progress = 0 progress > 100 -> this.progress = 100 else -> this.progress = progress } invalidate() //调用该方法后立即刷新视图 }fun getProgress():Int = progress }//根据自己喜爱给progressBar设置背景,线条粗细

  • 最后在MainActivity里面使用属性动画即可出现本文开头的动画
//MainActivity.kt package com.hefuwei.progressviewimport android.animation.ObjectAnimator import android.support.v7.app.AppCompatActivity import android.os.Bundle import kotlinx.android.synthetic.main.activity_main.*class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val animator = ObjectAnimator.ofInt(cb,"progress",100) animator.duration = 10000 animator.start() } }

最后附上github地址

    推荐阅读