一个简单的Android圆形ProgressBar
16lz
2021-12-04
使用kotlin实现一个简单的Android圆形ProgressBar
本自定义View功能比较简单,就是一个包含百分比的圆形进度条,先上结果图(新手,大神勿喷)
代码如下所示,支持padding设置,背景线条颜色设置
<?xml version="1.0" encoding="utf-8"?> "CircleProgressBar"> "backgroundColor" format="color" /> "textColor" format="color" /> "arcWidth" format="integer" /> //CircleProgressBar.ktpackage com.hefuwei.progressviewimport android.content.Contextimport android.graphics.Canvasimport android.graphics.Colorimport android.graphics.Paintimport android.graphics.Rectimport android.os.Buildimport android.support.annotation.RequiresApiimport android.util.AttributeSetimport 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设置背景,线条粗细<?xml version="1.0" encoding="utf-8"?>"http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.hefuwei.progressview.MainActivity"> <com.hefuwei.progressview.CircleProgressBar android:id="@+id/cb" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" app:arcWidth="40" app:backgroundColor="#fff" app:textColor="#000" />
- 最后在MainActivity里面使用属性动画即可出现本文开头的动画
//MainActivity.ktpackage com.hefuwei.progressviewimport android.animation.ObjectAnimatorimport android.support.v7.app.AppCompatActivityimport android.os.Bundleimport 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地址
更多相关文章
- android photoview 图片放大缩放功能 ImageView
- android:configChanges属性
- 设置TextView文字居中
- 使用迅雷代替SDK Manager快速下载Android(安卓)SDK相关
- 在Windows系统中使用NDK编译Android二进制文件并运行
- 安卓第三天---ViewPager控件实现滑动切换图片
- Android笔记-3
- Android使用Intent调用摄像头并获取照片
- android警告——Buttons in button bars should be border