自定义ProgressBar(包括自定义图片,带进度的圆形进度条、长方形进度条)
2016-05-31 15:20
716 查看
转载请注明原博客地址:/article/11896904.html
参考博客:http://blog.csdn.net/lmj623565791?viewmode=contents
ProgressBar简介
继承于View类,直接子类有AbsSeekBar和ContentLoadingProgressBar,其中AbsSeekBar的子类有SeekBar和RatingBar,可见这二者也是基于ProgressBar实现的。1、ProgressBar有两个进度,一个是Android:progress,另一个是android:secondaryProgress。后者主要是为缓存需要所涉及的,比如在看网络视频时候都会有一个缓存的进度条以及还要一个播放的进度,在这里缓存的进度就可以是android:secondaryProgress,而播放进度就是android:progress,有了secondProgress,可以很方便定制ProgressBar。
2、ProgressBar分为确定的和不确定的,确定的是我们能明确看到进度,相反不确定的就是不清楚、不确定一个操作需要多长时间来完成,这个时候就需要用的不确定的ProgressBar了。属性android:indeterminate如果设置为true的话,那么ProgressBar就可能是圆形的滚动条或者水平的滚动条(由样式决定),但是我们一般时候,是直接使用Style类型来区分圆形还是水平ProgressBar的。
3、ProgressBar的样式设定其实有两种方式,在API文档中说明的方式如下:
Widget.ProgressBar.Horizontal
Widget.ProgressBar.Small
Widget.ProgressBar.Large
Widget.ProgressBar.Inverse
Widget.ProgressBar.Small.Inverse
Widget.ProgressBar.Large.Inverse
使用的时候可以这样:style="@android:style/Widget.ProgressBar.Small",另外还有一种方式就是使用系统的attr,下面的方式是系统的style:
style="?android:attr/progressBarStyle"
style="?android:attr/progressBarStyleHorizontal"
style="?android:attr/progressBarStyleInverse"
style="?android:attr/progressBarStyleLarge"
style="?android:attr/progressBarStyleLargeInverse"
style="?android:attr/progressBarStyleSmall"
style="?android:attr/progressBarStyleSmallInverse"
style="?android:attr/progressBarStyleSmallTitle"
先看一下效果图
源代码下载地址:https://github.com/gdutxiaoxu/CustomProgressBar.git
1 修改ProgressBar的图片
1)第一个效果的实现非常简单
只需要修改ProgressBar的style即可
<style name="progressBar_custom_drawable" parent="@android:style/Widget.ProgressBar.Small"> <item name="android:indeterminateDrawable">@drawable/progressbar_circle_1</item> <item name="android:minWidth">25dp</item> <item name="android:minHeight">25dp</item> <item name="android:maxWidth">60dp</item> <item name="android:maxHeight">60dp</item> </style>
其中修改属性即可更改为我们想要的效果
<item name="android:indeterminateDrawable">@drawable/progressbar_circle_1</item>
2)这个形状我们可以借助代码实现
在Drawable目录下新建一个XML文件
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="360"> <shape android:innerRadiusRatio="3" android:shape="ring" android:thicknessRatio="8" android:useLevel="false"> <gradient android:centerColor="#FFFFFF" android:centerY="0.50" android:endColor="#1E90FF" android:startColor="#000000" android:type="sweep" android:useLevel="false" /> </shape> </rotate>
2 自定义长方形进度条
这种效果我们是通过继承ProgressBar实现的
a 先讲一下实现思路
横向那个进度条,主要是通过是通过Canvas类的drawLine()和drawText()方法实现的,
1)要解决的问题,怎样拿到拿到控件的宽度,(不了解的请先自行了解View的绘制原理,本篇博客的重点不在这里,就不详细说了,下面会给出测量的代码
2)拿到宽度以后,我们再通过getProgress()拿到进度,按比例控制绘制线的长短,这样就实现了。
为了控件使用起来方便,我们使用到了自定义属性,如果多自定义属性不熟悉的,建议参考鸿洋的这篇博客:http://blog.csdn.net/lmj623565791/article/details/45022631
下面给出源代码
1)在value目录下新建attr_progress_bar xml文件
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="BaseProgressBar"> <attr name="progress_unreached_color" format="color" /> <attr name="progress_reached_color" format="color" /> <attr name="progress_reached_bar_height" format="dimension" /> <attr name="progress_unreached_bar_height" format="dimension" /> <attr name="progress_text_size" format="dimension" /> <attr name="progress_text_color" format="color" /> <attr name="progress_text_offset" format="dimension" /> <attr name="progress_text_visibility" format="enum"> <enum name="visible" value="0" /> <enum name="invisible" value="1" /> </attr> </declare-styleable> <declare-styleable name="RoundProgressBarWidthNumber"> <attr name="radius" format="dimension" /> </declare-styleable> </resources>2)在构造器里面获取我们的自定义属性,为了代码的复用,我们把它放到基类BaseProgressBar
/** * get the styled attributes * * @param attrs */ private void obtainStyledAttributes(AttributeSet attrs) { // init values from custom attributes final TypedArray attributes = getContext().obtainStyledAttributes( attrs, R.styleable.BaseProgressBar); mTextColor = attributes .getColor( R.styleable.BaseProgressBar_progress_text_color, DEFAULT_TEXT_COLOR); mTextSize = (int) attributes.getDimension( R.styleable.BaseProgressBar_progress_text_size, mTextSize); mReachedBarColor = attributes .getColor( R.styleable.BaseProgressBar_progress_reached_color, mTextColor); mUnReachedBarColor = attributes .getColor( R.styleable.BaseProgressBar_progress_unreached_color, DEFAULT_COLOR_UNREACHED_COLOR); mReachedProgressBarHeight = (int) attributes .getDimension( R.styleable.BaseProgressBar_progress_reached_bar_height, mReachedProgressBarHeight); mUnReachedProgressBarHeight = (int) attributes .getDimension( R.styleable.BaseProgressBar_progress_unreached_bar_height, mUnReachedProgressBarHeight); mTextOffset = (int) attributes .getDimension( R.styleable.BaseProgressBar_progress_text_offset, mTextOffset); int textVisible = attributes .getInt(R.styleable.BaseProgressBar_progress_text_visibility, VISIBLE); if (textVisible != VISIBLE) { mIfDrawText = false; } attributes.recycle(); } public BaseProgressBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); obtainStyledAttributes(attrs); mPaint.setTextSize(mTextSize); mPaint.setColor(mTextColor); }
3)在onMeasure里面拿到我们空间的高度
<pre name="code" class="java">@Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = measureHeight(heightMeasureSpec); setMeasuredDimension(width, height); mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft(); } private int measureHeight(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); // 测量模式等于 MeasureSpec.EXACTLY,交给系统自己处理 if (specMode == MeasureSpec.EXACTLY) { result = specSize; // 测量模式不等于 MeasureSpec.EXACTLY } else { // 测量模式等于MeasureSpec.UNSPECIFIE的时候自己处理 float textHeight = (mPaint.descent() - mPaint.ascent()); result = (int) (getPaddingTop() + getPaddingBottom() + Math.max( Math.max(mReachedProgressBarHeight, mUnReachedProgressBarHeight), Math.abs(textHeight))); // 测量模式等于MeasureSpec.AT_MOST的时候,取较小的一个 if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; }
4)在onDraw里面绘制
@Override protected synchronized void onDraw(Canvas canvas) { canvas.save(); canvas.translate(getPaddingLeft(), getHeight() / 2); boolean noNeedBg = false; float radio = getProgress() * 1.0f / getMax(); float progressPosX = (int) (mRealWidth * radio); String text = getProgress() + "%"; // mPaint.getTextBounds(text, 0, text.length(), mTextBound); float textWidth = mPaint.measureText(text); float textHeight = (mPaint.descent() + mPaint.ascent()) / 2; if (progressPosX + textWidth > mRealWidth) { progressPosX = mRealWidth - textWidth; noNeedBg = true; } // draw reached bar float endX = progressPosX - mTextOffset / 2; if (endX > 0) { mPaint.setColor(mReachedBarColor); mPaint.setStrokeWidth(mReachedProgressBarHeight); canvas.drawLine(0, 0, endX, 0, mPaint); } // draw progress bar // measure text bound if (mIfDrawText) { mPaint.setColor(mTextColor); canvas.drawText(text, progressPosX, -textHeight, mPaint); } // draw unreached bar if (!noNeedBg) { float start = progressPosX + mTextOffset / 2 + textWidth; mPaint.setColor(mUnReachedBarColor); mPaint.setStrokeWidth(mUnReachedProgressBarHeight); canvas.drawLine(start, 0, mRealWidth, 0, mPaint); } canvas.restore(); }
到这里,实现思已经完毕
源代码下载地址:https://github.com/gdutxiaoxu/CustomProgressBar.git
3 自定义圆形进度条
实现思路
1)继承BaseProgressBar,在构造器里面获取我们需要的自定义属性
2)在onMeasure里面拿到我们空间的高度
3)在onDraw里面绘制圆和文本(先绘制一个细一点的圆,然后绘制一个粗一点的弧度,二者叠在一起就行。文本呢,绘制在中间)
代码如下
package com.xujun.administrator.customprogressbar; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint.Cap; import android.graphics.Paint.Style; import android.graphics.RectF; import android.util.AttributeSet; public class RoundProgressBarWidthNumber extends BaseProgressBar { /** * mRadius of view */ private int mRadius = dp2px(30); private int mMaxPaintWidth; public RoundProgressBarWidthNumber(Context context) { this(context, null); } public RoundProgressBarWidthNumber(Context context, AttributeSet attrs) { super(context, attrs); mReachedProgressBarHeight = (int) (mUnReachedProgressBarHeight * 2.5f); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressBarWidthNumber); mRadius = (int) ta.getDimension( R.styleable.RoundProgressBarWidthNumber_radius, mRadius); ta.recycle(); mPaint.setStyle(Style.STROKE); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStrokeCap(Cap.ROUND); } /** * 这里默认在布局中padding值要么不设置,要么全部设置 */ @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mMaxPaintWidth = Math.max(mReachedProgressBarHeight, mUnReachedProgressBarHeight); int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft() + getPaddingRight(); int width = resolveSize(expect, widthMeasureSpec); int height = resolveSize(expect, heightMeasureSpec); int realWidth = Math.min(width, height); mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2; setMeasuredDimension(realWidth, realWidth); } @Override protected synchronized void onDraw(Canvas canvas) { String text = getProgress() + "%"; float textWidth = mPaint.measureText(text); float textHeight = (mPaint.descent() + mPaint.ascent()) / 2; canvas.save(); canvas.translate(getPaddingLeft() + mMaxPaintWidth / 2, getPaddingTop() + mMaxPaintWidth / 2); mPaint.setStyle(Style.STROKE); // draw unreaded bar mPaint.setColor(mUnReachedBarColor); mPaint.setStrokeWidth(mUnReachedProgressBarHeight); canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); // draw reached bar mPaint.setColor(mReachedBarColor); mPaint.setStrokeWidth(mReachedProgressBarHeight); float sweepAngle = getProgress() * 1.0f / getMax() * 360; canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2), 0, sweepAngle, false, mPaint); // draw text mPaint.setStyle(Style.FILL); canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight, mPaint); canvas.restore(); } }源代码下载地址:https://github.com/gdutxiaoxu/CustomProgressBar.git
转载请注明原博客地址:/article/11896904.html
参考博客:http://blog.csdn.net/lmj623565791?viewmode=contents
相关文章推荐
- 程序编译与代码优化
- 你的前500位种子用户是怎么来的?
- 把一个字符串里符合表情文字标签的地方全部替换为相应的图片的方法
- 给UILabel 或者 UIButton标题加下划线
- 关于AngularJS的一些基础总结
- React Uncaught TypeError: _react2.default.findDOMNode is not a function
- Codeforces Round #202 (Div. 2) B. Color the Fence
- Android代码中设置字体大小
- bootstrap Table 后台交互
- loadrunner支持的浏览器版本
- json解析TypeToken的用法(最外层是集合)
- Bootstrap 3 与 Foundation 5
- AngularJS之Route(六)
- 完美解决Informix的中文乱码问题
- 科学计数法 与 普通数字 转换
- SQL连接(join)
- 无奈的事情是什么
- php 共享内存学习(APC扩展)
- 漫谈技术选型
- Android Studio 自定义快捷键