Android 自定义进度条

文章目录

    • Android 自定义进度条
      • 效果
      • 目录
      • 前言
      • 正文
        • `HorizontalProgressBarWithNumber`
        • 实现
      • 总结
      • 感谢

效果

国际惯例,效果图奉上

目录

前言

写在前面,由于之前其实已经写了部分自定义View的方法,所以本来应该按照之前的系列,来进行下载暂停动画进度条,但是我把之前的圆形进度条和开始暂停动画效果合并后,出现了一点小问题,让我发现之前写的自定义View,没有使我真正的了解自定义View,那么我觉得还是有很大的问题;那么之后依旧会努力的写自定义View,初步先写静态的自定义View,之后,加上动画的自定义VIew,后续在加上相应的触摸事件,努力的把自定义VIew的方法方式全部给记录下来;努力的融汇贯通。

正文

HorizontalProgressBarWithNumber

横向的进度条;里面有详细的注释

  1. 首先继承自ProgressBar,这个是对基础的ProgressBar 进行进一步的自定义,

    public class HorizontalProgressBarWithNumber extends ProgressBar{    ******}
  2. 当我们想要自定义VIew的时候,先要构思效果,那么就要设置各种属性,如下

/** * 设置各种默认值 */private static final int DEFAULT_TEXT_SIZE = 10;private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;/** * painter of all drawing things  所有画图所用的画笔 */protected Paint mPaint = new Paint();/** * color of progress number  进度号码的颜色 */protected int mTextColor = DEFAULT_TEXT_COLOR;/** * size of text (sp)  文本的大小 */protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);/** * offset of draw progress  进度条文本补偿宽度 */protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);/** * height of reached progress bar  进度条高度  */protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);/** * color of reached bar   成功的文本颜色 */protected int mReachedBarColor = DEFAULT_TEXT_COLOR;/** * color of unreached bar 未完成的bar颜色 */protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;/** * height of unreached progress bar  未覆盖的进度条高度 */protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);/** * view width except padding  除padding外的视图宽度 */protected int mRealWidth;protected boolean mIfDrawText = true;protected static final int VISIBLE = 0;
  1. 自定义构造函数
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs){this(context, attrs, 0);}public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,int defStyle){super(context, attrs, defStyle);obtainStyledAttributes(attrs);//初始化参数mPaint.setTextSize(mTextSize);//文本大小mPaint.setColor(mTextColor);//文本颜色}
  1. 接下来就是初始化的代码:
/** * get the styled attributes  获取属性的样式 *  * @param attrs */private void obtainStyledAttributes(AttributeSet attrs){// init values from custom attributesfinal TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBarWithNumber);mTextColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_text_color,DEFAULT_TEXT_COLOR);mTextSize = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_size,mTextSize);mReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,mTextColor);mUnReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,DEFAULT_COLOR_UNREACHED_COLOR);mReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,mReachedProgressBarHeight);mUnReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,mUnReachedProgressBarHeight);mTextOffset = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,mTextOffset);int textVisible = attributes.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,VISIBLE);if (textVisible != VISIBLE){mIfDrawText = false;}attributes.recycle();}
  1. 上面当中的参数和属性都在attr.xml中声明的,如下
<resources>   <declare-styleable name="HorizontalProgressBarWithNumber">       <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>
  1. 接下来,我们要重写onMeasure方法,在其中获取父控件传递过来的参数

    protected synchronized void onMeasure(int widthMeasureSpec,int heightMeasureSpec){int width = MeasureSpec.getSize(widthMeasureSpec);int height = measureHeight(heightMeasureSpec);//高度setMeasuredDimension(width, height);//必须调用该方法来存储View经过测量的到的宽度和高度mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();//真正的宽度值是减去左右padding}
  2. 其中measureHeight() 方法是获取视图的高度,视图的样式中拥有进度条和文本,要判断文本的高度和进度条的高度;

/** * EXACTLY:父控件告诉我们子控件了一个确定的大小,你就按这个大小来布局。比如我们指定了确定的dp值和macth_parent的情况。  *AT_MOST:当前控件不能超过一个固定的最大值,一般是wrap_content的情况。  *UNSPECIFIED:当前控件没有限制,要多大就有多大,这种情况很少出现。 * @param measureSpec   * @return  视图的高度 */private int measureHeight(int measureSpec){int result = 0;int specMode = MeasureSpec.getMode(measureSpec);//父布局告诉我们控件的类型int specSize = MeasureSpec.getSize(measureSpec);//父布局传过来的视图大小if (specMode == MeasureSpec.EXACTLY){result = specSize;} else{/** * mPaint.descent() 最高点的高度 * mPaint.ascent() 最低点的高度 */float textHeight = (mPaint.descent() - mPaint.ascent());// 设置文本的高度/** * Math.abs() 返回绝对值 *  Math.max 返回最大值 *  Math.min 返回最小值 */result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachedProgressBarHeight,mUnReachedProgressBarHeight), Math.abs(textHeight)));if (specMode == MeasureSpec.AT_MOST){result = Math.min(result, specSize);}}return result;}
  1. 以上全部完成后,就可以开始onDraw()方法了;
/** * 开始画 */@Overrideprotected synchronized void onDraw(Canvas canvas){canvas.save();/** * 设置偏移后的坐标原点 以原来为基础上偏移后, 例如: (100,100), translate(1,1), 坐标原点(101,101); */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){//当文本和当前进度的宽度大于bar的宽度时progressPosX = mRealWidth - textWidth;noNeedBg = true;}// draw reached bar   画出barfloat 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 boundif (mIfDrawText){//绘制文本mPaint.setColor(mTextColor);canvas.drawText(text, progressPosX, -textHeight, mPaint);}// draw unreached barif (!noNeedBg){//绘制未到达的进度条float start = progressPosX + mTextOffset / 2 + textWidth;mPaint.setColor(mUnReachedBarColor);mPaint.setStrokeWidth(mUnReachedProgressBarHeight);canvas.drawLine(start, 0, mRealWidth, 0, mPaint);}canvas.restore();}
  1. 在分享两个转换的方法
/** * dp 2 px *  * @param dpVal */protected int dp2px(int dpVal){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal, getResources().getDisplayMetrics());}/** * sp 2 px *  * @param spVal * @return */protected int sp2px(int spVal){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,spVal, getResources().getDisplayMetrics());}
  1. 最后自定义View 全部实现,奉上全部代码
public class HorizontalProgressBarWithNumber extends ProgressBar{/** * 设置各种默认值 */private static final int DEFAULT_TEXT_SIZE = 10;private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;/** * painter of all drawing things  所有画图所用的画笔 */protected Paint mPaint = new Paint();/** * color of progress number  进度号码的颜色 */protected int mTextColor = DEFAULT_TEXT_COLOR;/** * size of text (sp)  文本的大小 */protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);/** * offset of draw progress  进度条文本补偿宽度 */protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);/** * height of reached progress bar  进度条高度  */protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);/** * color of reached bar   成功的文本颜色 */protected int mReachedBarColor = DEFAULT_TEXT_COLOR;/** * color of unreached bar 未完成的bar颜色 */protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;/** * height of unreached progress bar  未覆盖的进度条高度 */protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);/** * view width except padding  除padding外的视图宽度 */protected int mRealWidth;protected boolean mIfDrawText = true;protected static final int VISIBLE = 0;public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs){this(context, attrs, 0);}public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,int defStyle){super(context, attrs, defStyle);obtainStyledAttributes(attrs);//初始化参数mPaint.setTextSize(mTextSize);//文本大小mPaint.setColor(mTextColor);//文本颜色}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec,int heightMeasureSpec){int width = MeasureSpec.getSize(widthMeasureSpec);int height = measureHeight(heightMeasureSpec);//高度setMeasuredDimension(width, height);//必须调用该方法来存储View经过测量的到的宽度和高度mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();//真正的宽度值是减去左右padding}/** * EXACTLY:父控件告诉我们子控件了一个确定的大小,你就按这个大小来布局。比如我们指定了确定的dp值和macth_parent的情况。  *AT_MOST:当前控件不能超过一个固定的最大值,一般是wrap_content的情况。  *UNSPECIFIED:当前控件没有限制,要多大就有多大,这种情况很少出现。 * @param measureSpec   * @return  视图的高度 */private int measureHeight(int measureSpec){int result = 0;int specMode = MeasureSpec.getMode(measureSpec);//父布局告诉我们控件的类型int specSize = MeasureSpec.getSize(measureSpec);//父布局传过来的视图大小if (specMode == MeasureSpec.EXACTLY){result = specSize;} else{/** * mPaint.descent() 最高点的高度 * mPaint.ascent() 最低点的高度 */float textHeight = (mPaint.descent() - mPaint.ascent());// 设置文本的高度/** * Math.abs() 返回绝对值 *  Math.max 返回最大值 *  Math.min 返回最小值 */result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachedProgressBarHeight,mUnReachedProgressBarHeight), Math.abs(textHeight)));if (specMode == MeasureSpec.AT_MOST){result = Math.min(result, specSize);}}return result;}/** * get the styled attributes  获取属性的样式 *  * @param attrs */private void obtainStyledAttributes(AttributeSet attrs){// init values from custom attributesfinal TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBarWithNumber);mTextColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_text_color,DEFAULT_TEXT_COLOR);mTextSize = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_size,mTextSize);mReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,mTextColor);mUnReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,DEFAULT_COLOR_UNREACHED_COLOR);mReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,mReachedProgressBarHeight);mUnReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,mUnReachedProgressBarHeight);mTextOffset = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,mTextOffset);int textVisible = attributes.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,VISIBLE);if (textVisible != VISIBLE){mIfDrawText = false;}attributes.recycle();}/** * 开始画 */@Overrideprotected synchronized void onDraw(Canvas canvas){canvas.save();/** * 设置偏移后的坐标原点 以原来为基础上偏移后, 例如: (100,100), translate(1,1), 坐标原点(101,101); */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){//当文本和当前进度的宽度大于bar的宽度时progressPosX = mRealWidth - textWidth;noNeedBg = true;}// draw reached bar   画出barfloat 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 boundif (mIfDrawText){mPaint.setColor(mTextColor);canvas.drawText(text, progressPosX, -textHeight, mPaint);}// draw unreached barif (!noNeedBg){float start = progressPosX + mTextOffset / 2 + textWidth;mPaint.setColor(mUnReachedBarColor);mPaint.setStrokeWidth(mUnReachedProgressBarHeight);canvas.drawLine(start, 0, mRealWidth, 0, mPaint);}canvas.restore();}/** * dp 2 px *  * @param dpVal */protected int dp2px(int dpVal){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal, getResources().getDisplayMetrics());}/** * sp 2 px *  * @param spVal * @return */protected int sp2px(int spVal){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,spVal, getResources().getDisplayMetrics());}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mRealWidth = w - getPaddingRight() - getPaddingLeft();}}

实现

  1. xml界面
            
  1. mainActivity() 实现
public class MainActivity extends Activity {private HorizontalProgressBarWithNumber mProgressBar;private Handler mHandler = new Handler() {public void handleMessage(android.os.Message msg) {int progress = mProgressBar.getProgress();mProgressBar.setProgress(++progress);if (progress >= 100) {mHandler.removeMessages(MSG_PROGRESS_UPDATE);}mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE, 100);};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mProgressBar = (HorizontalProgressBarWithNumber) findViewById(R.id.id_progressbar01);mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE);}
  1. 以上就是全部功能的实现了

总结

自定义View

  1. 先构思效果
  2. 根据效果 , 声明配置相应参数
  3. 想好怎么计算View的宽度和高度
  4. 如果画出来
  5. 开始做吧

感谢

这个是从鸿阳大神的Github上找到的例子,嗯,值得学习,感谢鸿阳大神;

更多相关文章

  1. Android应用开发——TextView控件属性列表
  2. 详细整理iOS中UITableView的性能优化
  3. Android(安卓)TextView属性详解
  4. android 弹出的软键盘遮挡住EditText文本框的解决方案
  5. Android(安卓)控件四 EditText 控件
  6. 理解android中ListFragment和Loader
  7. android EditText中的inputType
  8. Android中TextView和EditView常用属性设置
  9. Android(安卓)TextView使用及性能优化

随机推荐

  1. 我想找个这样的男朋友,要求高吗?
  2. 用 Python 读取巴菲特最近的持仓数据
  3. B站晚会大火的 140 万个理由!
  4. C语言的一些练习以及写一个猜数字游戏
  5. 巧用 Matplotlib 动画,让你的 Python 可
  6. 6、用户身份与文件权限
  7. 昨晚试试 数据行转列,差点翻了车
  8. 秋招拿了7个offer,分享一些反思和经验
  9. Ansible自动化部署服务
  10. 我对JDK15的简单理解