Android自定义View之圆形进度条总结
发布时间: 2017-05-17 16:35:38 作者:拓胜科技 来源:拓胜科技 浏览次数: 次
摘要:Android自定义View之圆形进度条总结,最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View 。在此对项目开发思路做个小结……
Android自定义View之圆形进度条总结,最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View 。在此对项目开发思路做个小结,欢迎大家 Star 和 Fork。
最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View 。在此对项目开发思路做个小结,欢迎大家 Star 和 Fork。
该项目总共实现了三种圆形进度条效果
先上效果图,有图才好说。
CircleProgress 效果图
DialProgress 和 WaveProgress 效果图
恩,那么接下来,就来讲讲怎么实现以上自定义进度条的效果。
圆形进度条
圆形进度条是第一个实现的进度条效果,用了我大半天的时间,实现起来并不复杂。
其思路主要可以分为以下几步:
首先,我们要测量出所绘制 View 的大小,即重写 onMeasure() 方法,代码如下:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(MiscUtil.measure(widthMeasureSpec, mDefaultSize), MiscUtil.measure(heightMeasureSpec, mDefaultSize)); }由于其他两个进度条类都需要实现 View 的测量,这里对代码进行了封装:
/** * 测量 View * * @param measureSpec * @param defaultSize View 的默认大小 * @return 测量出来的 View 大小 */ public static int measure(int measureSpec, int defaultSize) { int result = defaultSize; int specMode = View.MeasureSpec.getMode(measureSpec); int specSize = View.MeasureSpec.getSize(measureSpec); if (specMode == View.MeasureSpec.EXACTLY) { result = specSize; } else if (specMode == View.MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } return result; }关于 View 测量可以看下这篇博客 Android 自定义View 中的onMeasure的用法
接下来,在 onSizeChanged() 中计算绘制圆及文字所需的参数,考虑到屏幕旋转的情况,故未直接在 onMeasure() 方法中直接计算。这里以下面草图来讲解绘制计算过程中的注意事项,图丑,勿怪~
图中,外面蓝色矩形为 View,里面黑色矩形为圆的外接矩形,蓝色矩形和黑色矩形中间空白的地方为 View 的内边距(padding)。两个蓝色的圆其实是一个圆,代表圆的粗细,这是因为 Android 在绘制圆或者圆弧的时候是圆的边宽的中心与外接矩形相交,所以在计算的时候要考虑到内边距(padding) 和 圆与外接矩形的相交。
默认不考虑圆弧的宽度,绘制出来的效果如下:
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); Log.d(TAG, "onSizeChanged: w = " + w + "; h = " + h + "; oldw = " + oldw + "; oldh = " + oldh); //求圆弧和背景圆弧的最大宽度 float maxArcWidth = Math.max(mArcWidth, mBgArcWidth); //求最小值作为实际值 int minSize = Math.min(w - getPaddingLeft() - getPaddingRight() - 2 * (int) maxArcWidth, h - getPaddingTop() - getPaddingBottom() - 2 * (int) maxArcWidth); //减去圆弧的宽度,否则会造成部分圆弧绘制在外围 mRadius = minSize / 2; //获取圆的相关参数 mCenterPoint.x = w / 2; mCenterPoint.y = h / 2; //绘制圆弧的边界 mRectF.left = mCenterPoint.x - mRadius - maxArcWidth / 2; mRectF.top = mCenterPoint.y - mRadius - maxArcWidth / 2; mRectF.right = mCenterPoint.x + mRadius + maxArcWidth / 2; mRectF.bottom = mCenterPoint.y + mRadius + maxArcWidth / 2; //计算文字绘制时的 baseline //由于文字的baseline、descent、ascent等属性只与textSize和typeface有关,所以此时可以直接计算 //若value、hint、unit由同一个画笔绘制或者需要动态设置文字的大小,则需要在每次更新后再次计算 mValueOffset = mCenterPoint.y - (mValuePaint.descent() + mValuePaint.ascent()) / 2; mHintOffset = mCenterPoint.y * 2 / 3 - (mHintPaint.descent() + mHintPaint.ascent()) / 2; mUnitOffset = mCenterPoint.y * 4 / 3 - (mUnitPaint.descent() + mUnitPaint.ascent()) / 2; updateArcPaint(); Log.d(TAG, "onSizeChanged: 控件大小 = " + "(" + w + ", " + h + ")" + "圆心坐标 = " + mCenterPoint.toString() + ";圆半径 = " + mRadius + ";圆的外接矩形 = " + mRectF.toString());
关于 Android 中文字绘制可以参考以下两篇文章:
1. Android 自定义View学习(三)——Paint 绘制文字属性
2. measureText() vs .getTextBounds()
以上,已经基本完成了 View 绘制所需全部参数的计算。接下来就是绘制圆弧及文字了。