CircleNumberProgressBar:显示数字的圆形进度条
来源:互联网 发布:php个人博客网站代码 编辑:程序博客网 时间:2024/06/05 03:45
项目地址:https://github.com/AlarmZeng/CircleNumberProgressBar
圆形的ProgressBar是经常使用的控件,能够显示当前的进度,但有时候可能还不够直观,原有控件显示进度时并不能准确的知道当前进度是多少,又或是遇到项目需求需要在进度条中间加上数字显示,嗯……项目需求,所以这个时候就需要自己对原有的ProgressBar进行改造了,自己动手,丰衣足食嘛!
在原有的ProgressBar的基础上进行改造,那么就新建一个类CircleNumberProgressBar,并让其继承ProgressBar,接着我们需要先定义好CircleNumberProgressBar需要的相关属性
<declare-styleable name="CircleNumberProgressBar"> <!-- 圆的半径 --> <attr name="cnpb_circle_radius" format="dimension"/> <!-- 进度条的宽度 --> <attr name="cnpb_bar_width" format="dimension" /> <!-- 达到的进度颜色 --> <attr name="cnpb_reach_color" format="color" /> <!-- 未达到的进度颜色 --> <attr name="cnpb_unreach_color" format="color" /> <!-- 文字大小 --> <attr name="cnpb_text_size" format="dimension" /> <!-- 文字颜色 --> <attr name="cnpb_text_color" format="color" /> <!-- 文字是否显示 --> <attr name="cnpb_text_visibility" format="enum"> <enum name="invisible" value="0"/> <enum name="visible" value="1"/> </attr> <!-- 单位 --> <attr name="cnpb_unit" format="string"/> <!-- 单位是否显示 --> <attr name="cnpb_unit_visibility" format="enum"> <enum name="invisible" value="0"/> <enum name="visible" value="1"/> </attr> </declare-styleable>
我们还可以定义一个设置CircleNumberProgressBar的Style的一个属性
<attr name="styleCircleNumberProgressBar" format="reference" />
这样可以方便我们在styles文件中对CircleNumberProgressBar的属性进行统一设置,例如
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="styleCircleNumberProgressBar">@style/CircleNumberProgressBarTheme</item></style>
好了,定义并设置好属性之后,就需要在代码文件中对这些属性进行取值设置了,在构造函数中使用TypedArray对申明的属性进行取值,并在构造函数中对画笔Paint进行一些相关属性的设置
public CircleNumberProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleNumberProgressBar, defStyleAttr, R.style.CircleNumberProgressBar_Style); mRadius = typedArray.getDimensionPixelSize(R.styleable.CircleNumberProgressBar_cnpb_circle_radius, dp2px(30)); mBarWidth = typedArray.getDimensionPixelSize(R.styleable.CircleNumberProgressBar_cnpb_bar_width, dp2px(8)); mReachColor = typedArray.getColor(R.styleable.CircleNumberProgressBar_cnpb_reach_color, 0xFF303F9F); mUnReachColor = typedArray.getColor(R.styleable.CircleNumberProgressBar_cnpb_unreach_color, 0xFFD3D6DA); mTextSize = typedArray.getDimensionPixelSize(R.styleable.CircleNumberProgressBar_cnpb_text_size, sp2px(14)); mTextColor = typedArray.getColor(R.styleable.CircleNumberProgressBar_cnpb_text_color, 0xFF303F9F); mTextVisibility = typedArray.getInt(R.styleable.CircleNumberProgressBar_cnpb_text_visibility, VISIBLE); mUnit = typedArray.getString(R.styleable.CircleNumberProgressBar_cnpb_unit); mUnitVisibility = typedArray.getInt(R.styleable.CircleNumberProgressBar_cnpb_unit_visibility, VISIBLE); typedArray.recycle(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStrokeCap(Paint.Cap.ROUND); rectF = new RectF(0, 0, mRadius * 2, mRadius * 2); mBound = new Rect();}
设置属性之后,就到了自定义View的重点了,需要重写onMeasure()和onDraw()方法,在onMeasure()方法中需要对View进行测量,从而确定View的测量宽高,在CircleNumberProgressBar中,onMeasure()里面的测量代码如下
@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); int width = 0; int height = 0; switch (widthSpecMode) { case MeasureSpec.AT_MOST : width = Math.min(mRadius * 2 + getPaddingLeft() + getPaddingRight() + mBarWidth, widthSpecSize); break; case MeasureSpec.EXACTLY : width = widthSpecSize; break; case MeasureSpec.UNSPECIFIED : width = mRadius * 2 + getPaddingRight() + getPaddingLeft() + mBarWidth; break; } switch (heightSpecMode) { case MeasureSpec.AT_MOST : height = Math.min(mRadius * 2 + getPaddingTop() + getPaddingBottom() + mBarWidth, heightSpecSize); break; case MeasureSpec.EXACTLY : height = heightSpecSize; break; case MeasureSpec.UNSPECIFIED : height = mRadius * 2 + getPaddingTop() + getPaddingBottom() + mBarWidth; break; } int result = Math.min(width, height); setMeasuredDimension(result, result);}
在这里,会先分别获取宽高的测量模式SpecMode和对应测量模式下的规格大小SpecSize,接着会对测量模式SpecMode进行判定,并通过计算获取真正的宽高值,要注意的是,在计算时要把padding值算进去,否则会出现误差,在确定好宽高之后,再调用setMeasuredDimension方法设置宽高,这样就能确定View的大小了
测量了View的大小后,就要对View进行绘制了,我们需要绘制圆形,圆弧和文字,圆形是用来显示没有达到的进度,圆弧是显示达到的进度,文字则是在中间显示的进度值,看看代码
@Overrideprotected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); String text = mUnitVisibility == VISIBLE ? getProgress() + mUnit : getProgress() + ""; float baseline = getMeasuredHeight() / 2 + mPaint.getTextSize() / 2 - mPaint.getFontMetrics().descent - getPaddingTop(); canvas.save(); canvas.translate(getPaddingLeft() + mBarWidth / 2, getPaddingTop() + mBarWidth / 2); mPaint.setStyle(Paint.Style.STROKE); //先绘制未达到的进度条 mPaint.setColor(mUnReachColor); mPaint.setStrokeWidth(mBarWidth); canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); //再绘制已经达到的进度条 mPaint.setColor(mReachColor); mPaint.setStrokeWidth(mBarWidth); float angle = getProgress() * 1.0f / getMax() * 360; canvas.drawArc(rectF, 0, angle, false, mPaint); //绘制文字 if (mTextVisibility == VISIBLE) { mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(mTextColor); mPaint.setTextSize(mTextSize); mPaint.getTextBounds(text, 0, text.length(), mBound); canvas.drawText(text, mRadius - mBound.width() / 2, baseline, mPaint); } canvas.restore();}
在绘制时,需要先调用canvas.save()方法保存画布状态,以免影响后续操作。在绘制圆形时,需要设置画笔的Style为STROKE表示空心,再调用canvas.drawCircle方法绘制圆形,其圆心的x,y坐标和半径都是一样的
接着绘制进度条,这里是要绘制圆弧了,再绘制之前需要先计算圆弧的角度,这个比较简单,根据当前值 / 最大值 * 360
的公式计算就可以了,在绘制圆弧时参数还需要一个RectF,这是用来指定绘制圆弧的外部巨星区域,这个只要设置其长高为半径的两倍就可以了rectF = new RectF(0, 0, mRadius * 2, mRadius * 2);
最后是绘制文字,绘制文字时要将画笔的Style设置为FILL,接着我们需要知道文字的宽度,可以通过调用mPaint.getTextBounds方法先获取到文字的边界,再确定宽度,注意的是在canvas.drawText的方法中,第三个参数y是表示文字的基线baseline在屏幕上的位置,所以要先计算基线baseline的高,这样才能把文字准确的绘制
绘制完成后就可进行使用啦,直接在xml文件上进行调用就可以了
<com.zht.circlenumberprogressbar.widget.CircleNumberProgressBar android:id="@+id/cnpb_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" app:cnpb_circle_radius="50dp" />
属性值可以直接在xml文件设置,也可以在styles文件进行设置
<style name="CircleNumberProgressBarTheme" parent="CircleNumberProgressBar.Style"> <item name="cnpb_text_color">#FF303F9F</item> <item name="cnpb_reach_color">#FF303F9F</item> <item name="cnpb_unreach_color">#FFD3D6DA</item> <item name="cnpb_text_size">16sp</item> <item name="cnpb_text_color">#FF303F9F</item> <item name="cnpb_text_visibility">visible</item> <item name="cnpb_unit">%</item> <item name="cnpb_unit_visibility">visible</item></style>
好了,到这里CielceNumberProgressBar也就基本完成了,具体的代码可以到我的github查看,项目地址:https://github.com/AlarmZeng/CircleNumberProgressBar,觉得不错的可以star或者follow,哈哈
- CircleNumberProgressBar:显示数字的圆形进度条
- 使用带进度显示的圆形进度条
- Android 自定义带数字的圆形进度条和中间是文字的圆形进度条View
- Android带圆形数字进度的自定义进度条
- Android 带百分比数字的水平、圆形进度条
- Android开发 自制圆形带进度显示的进度条
- Android开发 自制圆形带进度显示的进度条
- 带动画效果的圆形进度条显示定时器倒计时
- 自定义的圆形进度条
- 简单的进度条,圆形进度条(一)
- 简单的圆形的进度条
- 自定义圆形进度条显示MP3播放进度
- ios AFNetworking 圆形进度条下载,显示百分比
- 自定义圆形进度条指数显示笔记
- 自定义漂亮的圆形进度条
- 自定义漂亮的圆形进度条
- 圆形进度条的实现方法
- Libgdx 圆形进度条的实现
- [学习笔记]Android系统功能之基础知识(传感器、无线传输与媒体硬件功能开发)
- hihocoder1239(递推)
- markdown段首空格/段首缩进问题
- oracle数据库常用的99条查询语句
- LeetCode-566. Reshape the Matrix
- CircleNumberProgressBar:显示数字的圆形进度条
- 杭电题型分类
- P-value个人理解
- PHP函数表
- LIBSVM的简易入门
- 装了新版本的JDK 打开CMD 发现还是原来的版本
- 3. Longest Substring Without Repeating Characters
- C语言青葱之路-指针练习-输入整型数组,用指针输出
- CentOS安装Maven