android 自定义 View(4)- 进度条(ProgressBar)

2024-06-21 15:32

本文主要是介绍android 自定义 View(4)- 进度条(ProgressBar),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考:

Android 打造形形色色的进度条 实现可以如此简单
daimajia/NumberProgressBar


自定义视图(View)是 Android 开发的一个进阶内容。随着开发的深入,肯定会出现系统提供的基础控件不符合需求的情况。一方面通过组合基础控件以形成新的布局,另一方面可以通过自定义控件的方式来更加灵活的实现需求

自定义视图涉及到 Android 系统许多方面的内容,下面根据自己的理解顺序来讲一讲如何自定义视图


主要内容

  1. 进度条浅析
  2. 水平进度条
  3. 文本进度条
  4. 圆形进度条

参考:ProgressBar

进度条是 Android 应用中经常使用的一种控件,在文件上传下载时,用进度条显示当前上传或者下载进度,更有利于用户体验

最简单的进度条应该就是一条线段,用两种颜色表示已完成和未完成,如果在线段上加上文本显示,更有利于说明当前进度,另外,还可以制作圆形进度条


水平进度条

学习 hongyang 的自定义进度条,利用 Android 内置的 ProgressBar,重新绘制进度条。

下面实现最简单的水平进度条

水平进度条浅析

实现水平进度条,首先是确定进度条的颜色,可以先默认设置已完成和未完成进度条的颜色,然后利用控件 ProgressBar 的属性设置当前进度以及总进度值

通过自定义属性,可以设置颜色值

根据控件长宽属性,进行尺寸的重新测量,确定进度条的大小,实现更完善的水平进度条

实现进度条

新建 SimpleProgressbar.java,继承 Android 控件 ProgressBar设置进度条的颜色,在 onDraw 方法中利用 ProgressBar 提供的属性 android:progress 设置当前进度

public class SimpleProgressbar extends ProgressBar {private static final String TAG = "SimpleProgressbar";public static final int DEFAULT_UNREACHED_COLOR = 0xFF912CEE;public static final int DEFAULT_REACHED_COLOR = 0xFF54FF9F;/*** 画笔*/private Paint paint;/*** 未到达进度条颜色*/private int unreachedColor;/*** 已到达进度条颜色*/private int reachedColor;public SimpleProgressbar(Context context) {//        super(context);this(context, null);}public SimpleProgressbar(Context context, AttributeSet attrs) {//        super(context, attrs);this(context, attrs, 0);}public SimpleProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();unreachedColor = DEFAULT_UNREACHED_COLOR;reachedColor = DEFAULT_REACHED_COLOR;}@Overrideprotected synchronized void onDraw(Canvas canvas) {//        super.onDraw(canvas);// 获取画布的宽高int width = getWidth();int height = getHeight();// 获取进度条的实际宽高int lineWidth = width - getPaddingLeft() - getPaddingRight();int lineHeight = height - getPaddingTop() - getPaddingBottom();// 获取当前进度float ratio = getProgress() * 1.0f / getMax();// 获取未完成进度大小int unreachedWidth = (int) (lineWidth * (1 - ratio));// 获取已完成进度大小int reachedWidth = lineWidth - unreachedWidth;// 绘制已完成进度条,设置画笔颜色和大小paint.setColor(reachedColor);paint.setStrokeWidth(lineHeight);// 计算已完成进度条起点和终点的坐标int startX = getPaddingLeft();int startY = getHeight() / 2;int stopX = startX + reachedWidth;int stopY = startY;// 画线canvas.drawLine(startX, startY, stopX, stopY, paint);// 设置画笔颜色paint.setColor(unreachedColor);startX = getPaddingLeft() + reachedWidth;stopX = width - getPaddingRight();canvas.drawLine(startX, startY, stopX, stopY, paint);}}

布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.zj.progressnumber.MainActivity"><com.zj.progressnumber.SimpleProgressbarandroid:layout_width="match_parent"android:layout_height="30dp"android:layout_marginTop="30dp"android:background="@android:color/holo_orange_dark"android:padding="8dp"android:progress="30" /></android.support.design.widget.CoordinatorLayout>

这里写图片描述

每隔 500 毫秒增加进度条进度,实现如下:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final SimpleProgressbar spb = (SimpleProgressbar) findViewById(R.id.spb);final int max = spb.getMax();new Thread(new Runnable() {@Overridepublic void run() {int progress = spb.getProgress();while ((progress + 1) <= max) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}spb.setProgress(progress + 1);progress = progress + 1;}}}).start();}
}

这里写图片描述

自定义进度条颜色

自定义已完成进度条和未完成进度条的颜色

<?xml version="1.0" encoding="utf-8"?>
<resources><attr name="reachedColor" format="color" /><attr name="unreachedColor" format="color" /><declare-styleable name="SimpleProgressbar"><attr name="reachedColor" /><attr name="unreachedColor" /></declare-styleable></resources>

修改 SimpleProgressbar.java,增加自定义属性的查询:

public class SimpleProgressbar extends ProgressBar {private static final String TAG = "SimpleProgressbar";......public SimpleProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);...obtainStyledAttributes(context, attrs, defStyleAttr);}......private void obtainStyledAttributes(Context context, AttributeSet attrs, int defStyleAttr) {TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SimpleProgressbar, defStyleAttr, 0);int count = a.getIndexCount();for (int i = 0; i < count; i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.SimpleProgressbar_reachedColor:reachedColor = a.getColor(attr, DEFAULT_REACHED_COLOR);break;case R.styleable.SimpleProgressbar_unreachedColor:unreachedColor = a.getColor(attr, DEFAULT_UNREACHED_COLOR);break;}}a.recycle();}
}

修改布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:custom="http://schemas.android.com/apk/res/com.zj.progressnumber"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.zj.progressnumber.MainActivity"><com.zj.progressnumber.SimpleProgressbarandroid:id="@+id/spb"android:layout_width="match_parent"android:layout_height="30dp"android:layout_marginTop="30dp"android:background="@android:color/holo_orange_dark"android:padding="8dp"android:progress="30"custom:reachedColor="@android:color/holo_green_light"custom:unreachedColor="@android:color/holo_blue_light"/></android.support.design.widget.CoordinatorLayout>

这里写图片描述

修改程序,随机增加进度:

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final SimpleProgressbar spb = (SimpleProgressbar) findViewById(R.id.spb);final int max = spb.getMax();new Thread(new Runnable() {@Overridepublic void run() {int progress = spb.getProgress();int random = (int) (Math.random() * 10) + 1;random = (progress + random) <= max ? random : (max - progress);while ((progress + random) <= max) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}progress = progress + random;spb.setProgress(progress);if (progress == max)break;random = (int) (Math.random() * 10) + 1;random = (progress + random) <= max ? random : (max - progress);}}}).start();}
}

这里写图片描述

设定进度条宽高

在上面的代码中,如果进度条宽高设定为 wrap_content 模式,无法正常显示,修改代码,设定最小的宽和高

完整代码如下:

public class SimpleProgressbar extends ProgressBar {private static final String TAG = "SimpleProgressbar";public static final int DEFAULT_UNREACHED_COLOR = 0xFF912CEE;public static final int DEFAULT_REACHED_COLOR = 0xFF54FF9F;// 进度条默认高,单位为 dppublic static final int DEFAULT_LINE_HEIGHT = 2;// 进度条默认宽,单位为 dppublic static final int DEFAULT_LINE_WIDTH = 100;/*** 画笔*/private Paint paint;/*** 未到达进度条颜色*/private int unreachedColor;/*** 已到达进度条颜色*/private int reachedColor;/*** 默认进度条最小的高(不含内边距)*/private int minLineHeight;/*** 默认进度条最小的宽(不含内边距)*/private int minLineWidth;/*** 实际使用的进度条的高(不含内边距)*/private int lineHeight;/*** 实际使用的进度条的宽(不含内边距)*/private int lineWidth;public SimpleProgressbar(Context context) {//        super(context);this(context, null);}public SimpleProgressbar(Context context, AttributeSet attrs) {//        super(context, attrs);this(context, attrs, 0);}public SimpleProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();unreachedColor = DEFAULT_UNREACHED_COLOR;reachedColor = DEFAULT_REACHED_COLOR;minLineHeight = dp2px(DEFAULT_LINE_HEIGHT);minLineWidth = dp2px(DEFAULT_LINE_WIDTH);obtainStyledAttributes(context, attrs, defStyleAttr);}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int desiredWidth = minLineWidth + getPaddingLeft() + getPaddingRight();int desiredHeight = minLineHeight + getPaddingTop() + getPaddingBottom();int width;int height;if (widthMode == MeasureSpec.AT_MOST) {width = Math.min(widthSize, desiredWidth);} else {width = Math.max(widthSize, desiredWidth);}if (heightMode == MeasureSpec.AT_MOST) {height = Math.min(heightSize, desiredHeight);} else {height = Math.max(heightSize, desiredHeight);}setMeasuredDimension(width, height);}@Overrideprotected synchronized void onDraw(Canvas canvas) {//        super.onDraw(canvas);// 获取画布的宽高int width = getWidth();int height = getHeight();// 获取进度条的实际宽高int lineWidth = width - getPaddingLeft() - getPaddingRight();int lineHeight = height - getPaddingTop() - getPaddingBottom();// 获取当前进度float ratio = getProgress() * 1.0f / getMax();// 获取未完成进度大小int unreachedWidth = (int) (lineWidth * (1 - ratio));// 获取已完成进度大小int reachedWidth = lineWidth - unreachedWidth;// 绘制已完成进度条,设置画笔颜色和大小paint.setColor(reachedColor);paint.setStrokeWidth(lineHeight);// 计算已完成进度条起点和终点的坐标int startX = getPaddingLeft();int startY = getHeight() / 2;int stopX = startX + reachedWidth;int stopY = startY;// 画线canvas.drawLine(startX, startY, stopX, stopY, paint);// 设置画笔颜色paint.setColor(unreachedColor);startX = getPaddingLeft() + reachedWidth;stopX = width - getPaddingRight();canvas.drawLine(startX, startY, stopX, stopY, paint);}private void obtainStyledAttributes(Context context, AttributeSet attrs, int defStyleAttr) {TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SimpleProgressbar, defStyleAttr, 0);int count = a.getIndexCount();for (int i = 0; i < count; i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.SimpleProgressbar_reachedColor:reachedColor = a.getColor(attr, DEFAULT_REACHED_COLOR);break;case R.styleable.SimpleProgressbar_unreachedColor:unreachedColor = a.getColor(attr, DEFAULT_UNREACHED_COLOR);break;}}a.recycle();}/*** dp 2 px** @param dpVal*/protected int dp2px(int dpVal) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal, getResources().getDisplayMetrics());}
}

文本进度条

上面已实现了水平进度条,如果要在进度条上增加文本,需要考虑以下几点:

  • 如何平衡文本和进度条的大小
  • 如果插入文本

思路:判断文本的高和进度条的高,设置更大的值为文本进度条的高;文本值从 0% 变化到 100%,在水平进度条上固定预留出文本显示最大值的宽

首先还是先把文本进度条画出来,实现如下,新建 ZProgressbar.java

public class ZProgressbar extends ProgressBar {private static final String TAG = "SimpleProgressbar";public static final int DEFAULT_UNREACHED_COLOR = 0xFF7D9EC0;public static final int DEFAULT_REACHED_COLOR = 0xFFC1FFC1;public static final int DEFAULT_TEXT_COLOR = 0xFF0000CD;public static final String DEFAULT_TEXT = "100%";// 进度条默认高,单位为 dppublic static final int DEFAULT_LINE_HEIGHT = 2;// 进度条默认宽,单位为 dppublic static final int DEFAULT_LINE_WIDTH = 100;// 文本大小,单位为 sppublic static final int DEFAULT_TEXT_SIZE = 12;private Paint paint;private Rect textBound;private int reachedColor;private int unreachedColor;private int textColor;private int lineHeight;private int minLineHeight;private int minLineWidth;private int textSize;private int textHeight;private int textWidth;public ZProgressbar(Context context) {//        super(context);this(context, null);}public ZProgressbar(Context context, AttributeSet attrs) {//        super(context, attrs);this(context, attrs, 0);}public ZProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();textBound = new Rect();unreachedColor = DEFAULT_UNREACHED_COLOR;reachedColor = DEFAULT_REACHED_COLOR;textColor = DEFAULT_TEXT_COLOR;minLineHeight = dp2px(DEFAULT_LINE_HEIGHT);minLineWidth = dp2px(DEFAULT_LINE_WIDTH);textSize = sp2px(DEFAULT_TEXT_SIZE);// 计算文本的宽和高paint.setTextSize(textSize);paint.getTextBounds(DEFAULT_TEXT, 0, DEFAULT_TEXT.length(), textBound);textWidth = textBound.width();textHeight = textBound.height();}@Overrideprotected synchronized void onDraw(Canvas canvas) {//        super.onDraw(canvas);int width = getWidth();int height = getHeight();int contentWidth = width - getPaddingLeft() - getPaddingRight();lineHeight = height - getPaddingTop() - getPaddingBottom();float ratio = getProgress() * 1.0f / getMax();int unreachedWidth = (int) ((contentWidth - textWidth) * (1 - ratio));int reachedWidth = contentWidth - textWidth - unreachedWidth;paint.setColor(reachedColor);paint.setStrokeWidth(lineHeight);int startX = getPaddingLeft();int startY = height / 2;int stopX = getPaddingLeft() + reachedWidth;int stopY = height / 2;canvas.drawLine(startX, startY, stopX, stopY, paint);String currentText = getProgress() + "%";paint.getTextBounds(currentText, 0, currentText.length(), textBound);paint.setColor(textColor);paint.setTextSize(textSize);startX = getPaddingLeft() + reachedWidth + (textWidth - textBound.width()) / 2;Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();startY = (height - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;canvas.drawText(currentText, startX, startY, paint);paint.setColor(unreachedColor);paint.setStrokeWidth(lineHeight);startX = getPaddingLeft() + reachedWidth + textWidth;startY = height / 2;stopX = width - getPaddingRight();stopY = height / 2;canvas.drawLine(startX, startY, stopX, stopY, paint);}/*** 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());}
}

布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:custom="http://schemas.android.com/apk/res/com.zj.progressnumber"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="8dp"tools:context="com.zj.progressnumber.MainActivity"><com.zj.progressnumber.ZProgressbarandroid:id="@+id/zpb"android:layout_width="match_parent"android:layout_height="30dp"android:layout_marginTop="100dp"android:progress="10" /></android.support.design.widget.CoordinatorLayout>

这里写图片描述

程序实现如下:

这里写图片描述

接下里增加尺寸测量部分:

public class ZProgressbar extends ProgressBar {private static final String TAG = "SimpleProgressbar";public static final int DEFAULT_UNREACHED_COLOR = 0xFF7D9EC0;public static final int DEFAULT_REACHED_COLOR = 0xFFC1FFC1;public static final int DEFAULT_TEXT_COLOR = 0xFF0000CD;public static final String DEFAULT_TEXT = "100%";// 进度条默认高,单位为 dppublic static final int DEFAULT_LINE_HEIGHT = 2;// 进度条默认宽,单位为 dppublic static final int DEFAULT_LINE_WIDTH = 100;// 文本大小,单位为 sppublic static final int DEFAULT_TEXT_SIZE = 12;private Paint paint;private Rect textBound;private int reachedColor;private int unreachedColor;private int textColor;private int lineHeight;private int minLineHeight;private int minLineWidth;private int textSize;private int textHeight;private int textWidth;public ZProgressbar(Context context) {//        super(context);this(context, null);}public ZProgressbar(Context context, AttributeSet attrs) {//        super(context, attrs);this(context, attrs, 0);}public ZProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();textBound = new Rect();unreachedColor = DEFAULT_UNREACHED_COLOR;reachedColor = DEFAULT_REACHED_COLOR;textColor = DEFAULT_TEXT_COLOR;minLineHeight = dp2px(DEFAULT_LINE_HEIGHT);minLineWidth = dp2px(DEFAULT_LINE_WIDTH);textSize = sp2px(DEFAULT_TEXT_SIZE);}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);// 计算文本的宽和高paint.setTextSize(textSize);paint.getTextBounds(DEFAULT_TEXT, 0, DEFAULT_TEXT.length(), textBound);textWidth = textBound.width();textHeight = textBound.height();// 比较文本的高和线段的高int minHeight = textHeight > minLineHeight ? textHeight : minLineHeight;int desiredWidth = minLineWidth + getPaddingLeft() + getPaddingRight();int desiredHeight = minHeight + getPaddingTop() + getPaddingBottom();int width;int height;if (widthMode == MeasureSpec.AT_MOST) {width = desiredWidth;} else {width = Math.max(widthSize, desiredWidth);}if (heightMode == MeasureSpec.AT_MOST) {height = desiredHeight;lineHeight = minLineHeight;} else {height = Math.max(heightSize, desiredHeight);lineHeight = height - getPaddingLeft() - getPaddingRight();}setMeasuredDimension(width, height);}@Overrideprotected synchronized void onDraw(Canvas canvas) {//        super.onDraw(canvas);int width = getWidth();int height = getHeight();int contentWidth = width - getPaddingLeft() - getPaddingRight();float ratio = getProgress() * 1.0f / getMax();int unreachedWidth = (int) ((contentWidth - textWidth) * (1 - ratio));int reachedWidth = contentWidth - textWidth - unreachedWidth;paint.setColor(reachedColor);paint.setStrokeWidth(lineHeight);int startX = getPaddingLeft();int startY = height / 2;int stopX = getPaddingLeft() + reachedWidth;int stopY = height / 2;canvas.drawLine(startX, startY, stopX, stopY, paint);String currentText = getProgress() + "%";paint.getTextBounds(currentText, 0, currentText.length(), textBound);paint.setColor(textColor);paint.setTextSize(textSize);startX = getPaddingLeft() + reachedWidth + (textWidth - textBound.width()) / 2;Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();startY = (height - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;canvas.drawText(currentText, startX, startY, paint);paint.setColor(unreachedColor);paint.setStrokeWidth(lineHeight);startX = getPaddingLeft() + reachedWidth + textWidth;startY = height / 2;stopX = width - getPaddingRight();stopY = height / 2;canvas.drawLine(startX, startY, stopX, stopY, paint);}/*** 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());}
}

最后增加自定义属性,控制文本颜色,进度条颜色,文本大小以及是否显示文本

完整代码如下:

public class ZProgressbar extends ProgressBar {private static final String TAG = "SimpleProgressbar";public static final int DEFAULT_UNREACHED_COLOR = 0xFF7D9EC0;public static final int DEFAULT_REACHED_COLOR = 0xFFC1FFC1;public static final int DEFAULT_TEXT_COLOR = 0xFF0000CD;public static final String DEFAULT_TEXT = "100%";// 进度条默认高,单位为 dppublic static final int DEFAULT_LINE_HEIGHT = 2;// 进度条默认宽,单位为 dppublic static final int DEFAULT_LINE_WIDTH = 100;// 文本大小,单位为 sppublic static final int DEFAULT_TEXT_SIZE = 8;private Paint paint;private Rect textBound;private int reachedColor;private int unreachedColor;private int textColor;private int lineHeight;private int minLineHeight;private int minLineWidth;private int textSize;private int textHeight;private int textWidth;private boolean isShowText;public ZProgressbar(Context context) {//        super(context);this(context, null);}public ZProgressbar(Context context, AttributeSet attrs) {//        super(context, attrs);this(context, attrs, 0);}public ZProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();textBound = new Rect();unreachedColor = DEFAULT_UNREACHED_COLOR;reachedColor = DEFAULT_REACHED_COLOR;textColor = DEFAULT_TEXT_COLOR;minLineHeight = dp2px(DEFAULT_LINE_HEIGHT);minLineWidth = dp2px(DEFAULT_LINE_WIDTH);textSize = sp2px(DEFAULT_TEXT_SIZE);isShowText = true;obtainStyledAttributes(context, attrs, defStyleAttr);}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);// 计算文本的宽和高paint.setTextSize(textSize);paint.getTextBounds(DEFAULT_TEXT, 0, DEFAULT_TEXT.length(), textBound);textWidth = textBound.width();textHeight = textBound.height();int minHeight = minLineHeight;if (isShowText) {// 比较文本的高和线段的高minHeight = textHeight > minLineHeight ? textHeight : minLineHeight;}int desiredWidth = minLineWidth + getPaddingLeft() + getPaddingRight();int desiredHeight = minHeight + getPaddingTop() + getPaddingBottom();int width;int height;if (widthMode == MeasureSpec.AT_MOST) {width = desiredWidth;} else {width = Math.max(widthSize, desiredWidth);}if (heightMode == MeasureSpec.AT_MOST) {height = desiredHeight;lineHeight = minLineHeight;} else {height = Math.max(heightSize, desiredHeight);lineHeight = height - getPaddingLeft() - getPaddingRight();}setMeasuredDimension(width, height);}@Overrideprotected synchronized void onDraw(Canvas canvas) {//        super.onDraw(canvas);int width = getWidth();int height = getHeight();int contentWidth = width - getPaddingLeft() - getPaddingRight();if (isShowText) {float ratio = getProgress() * 1.0f / getMax();int unreachedWidth = (int) ((contentWidth - textWidth) * (1 - ratio));int reachedWidth = contentWidth - textWidth - unreachedWidth;paint.setColor(reachedColor);paint.setStrokeWidth(lineHeight);int startX = getPaddingLeft();int startY = height / 2;int stopX = getPaddingLeft() + reachedWidth;int stopY = height / 2;canvas.drawLine(startX, startY, stopX, stopY, paint);String currentText = getProgress() + "%";paint.getTextBounds(currentText, 0, currentText.length(), textBound);paint.setColor(textColor);paint.setTextSize(textSize);startX = getPaddingLeft() + reachedWidth + (textWidth - textBound.width()) / 2;Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();startY = (height - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;canvas.drawText(currentText, startX, startY, paint);paint.setColor(unreachedColor);paint.setStrokeWidth(lineHeight);startX = getPaddingLeft() + reachedWidth + textWidth;startY = height / 2;stopX = width - getPaddingRight();stopY = height / 2;canvas.drawLine(startX, startY, stopX, stopY, paint);} else {float ratio = getProgress() * 1.0f / getMax();int unreachedWidth = (int) (contentWidth * (1 - ratio));int reachedWidth = contentWidth - unreachedWidth;paint.setColor(reachedColor);paint.setStrokeWidth(lineHeight);int startX = getPaddingLeft();int startY = height / 2;int stopX = getPaddingLeft() + reachedWidth;int stopY = height / 2;canvas.drawLine(startX, startY, stopX, stopY, paint);paint.setColor(unreachedColor);paint.setStrokeWidth(lineHeight);startX = getPaddingLeft() + reachedWidth;startY = height / 2;stopX = width - getPaddingRight();stopY = height / 2;canvas.drawLine(startX, startY, stopX, stopY, paint);}}private void obtainStyledAttributes(Context context, AttributeSet attrs, int defStyleAttr) {TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ZProgressbar, defStyleAttr, 0);int count = a.getIndexCount();for (int i = 0; i < count; i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.ZProgressbar_reachedColor:reachedColor = a.getColor(attr, DEFAULT_REACHED_COLOR);break;case R.styleable.ZProgressbar_unreachedColor:unreachedColor = a.getColor(attr, DEFAULT_UNREACHED_COLOR);break;case R.styleable.ZProgressbar_textColor:textColor = a.getColor(attr, DEFAULT_TEXT_COLOR);break;case R.styleable.ZProgressbar_textSize:textSize = sp2px((int) a.getDimension(attr, DEFAULT_TEXT_SIZE));break;case R.styleable.ZProgressbar_isShowText:isShowText = a.getBoolean(attr, true);break;}}a.recycle();}/*** 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());}
}

资源文件如下:

<?xml version="1.0" encoding="utf-8"?>
<resources><attr name="reachedColor" format="color" /><attr name="unreachedColor" format="color" /><attr name="textSize" format="dimension" /><attr name="textColor" format="color" /><attr name="isShowText" format="boolean" /><declare-styleable name="SimpleProgressbar"><attr name="reachedColor" /><attr name="unreachedColor" /></declare-styleable><declare-styleable name="ZProgressbar"><attr name="reachedColor" /><attr name="unreachedColor" /><attr name="textSize" /><attr name="textColor" /><attr name="isShowText" /></declare-styleable></resources>

布局如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="8dp"tools:context="com.zj.progressnumber.MainActivity"><com.zj.progressnumber.SimpleProgressbarandroid:id="@+id/spb"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dp"android:background="@android:color/holo_green_light"android:padding="8dp"android:progress="10"app:reachedColor="@android:color/holo_orange_light"app:unreachedColor="@color/colorAccent" /><com.zj.progressnumber.ZProgressbarandroid:id="@+id/zpb"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="100dp"android:background="@android:color/holo_green_light"android:padding="8dp"android:progress="10"app:reachedColor="@color/colorPrimary"app:textColor="@android:color/holo_orange_dark"app:unreachedColor="@color/colorAccent" /></android.support.design.widget.CoordinatorLayout>

程序如下:

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final SimpleProgressbar spb = (SimpleProgressbar) findViewById(R.id.spb);addProgress(spb);ZProgressbar zpb = (ZProgressbar) findViewById(R.id.zpb);addProgress(zpb);}private void addProgress(final ProgressBar spb) {final int max = spb.getMax();new Thread(new Runnable() {@Overridepublic void run() {int progress = spb.getProgress();int random = (int) (Math.random() * 10) + 1;random = (progress + random) <= max ? random : (max - progress);while ((progress + random) <= max) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}progress = progress + random;spb.setProgress(progress);if (progress == max)break;random = (int) (Math.random() * 10) + 1;random = (progress + random) <= max ? random : (max - progress);}}}).start();}
}

圆形进度条

画圆形进度条,需要绘制 3 个部分:圆,圆弧,文本

其中 表示进度条,圆弧 表示当前进度,文本 显示在圆中间

最简单的圆形进度条

老规矩,先实现最简单的圆形进度条:圆和圆弧。新建 RoundProgressbar.java

public class RoundProgressbar extends ProgressBar {/*** 画笔*/private Paint paint;/*** 绘制圆弧时使用*/private RectF rectF;/*** 圆半径*/int radius;/*** 圆心横坐标*/int centerX;/*** 圆心纵坐标*/int centerY;public RoundProgressbar(Context context) {
//        super(context);this(context, null);}public RoundProgressbar(Context context, AttributeSet attrs) {
//        super(context, attrs);this(context, attrs, 0);}public RoundProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();// 设置画笔宽度为 30 像素paint.setStrokeWidth(30);rectF = new RectF();}@Overrideprotected synchronized void onDraw(Canvas canvas) {
//        super.onDraw(canvas);int width = getWidth();int height = getHeight();int contentWidth = width - getPaddingLeft() - getPaddingRight();int contentHeight = height - getPaddingTop() - getPaddingBottom();// 设置圆心为画布正中心radius = contentWidth >= contentHeight ? contentWidth / 2 : contentHeight / 2;centerX = width / 2;centerY = height / 2;// 仅绘制边paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.BLUE);canvas.drawCircle(centerX, centerY, radius, paint);rectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);float ratio = getProgress() * 1.0f / getMax();int angle = (int) (ratio * 360);paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);canvas.drawArc(rectF, 0, angle, false, paint);}
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="8dp"tools:context="com.zj.progressnumber.MainActivity"><com.zj.progressnumber.RoundProgressbarandroid:id="@+id/rpb"android:layout_width="200dp"android:layout_height="200dp"android:background="@android:color/holo_green_light"android:progress="50"android:padding="20dp" /></android.support.design.widget.CoordinatorLayout>

这里写图片描述

实现:

这里写图片描述

自定义属性和尺寸测量

在上面的基础上增加画笔宽度的自定义属性,以及进行尺寸测量

public class RoundProgressbar extends ProgressBar {// 设置默认圆大小,单位为 dppublic static final int DEFAULT_RADIUS = 30;// 设置默认画笔宽度,单位为 dppublic static final int DEFAULT_STROKE_WIDTH = 1;/*** 画笔*/private Paint paint;/*** 绘制圆弧时使用*/private RectF rectF;/*** 圆半径*/int radius;/*** 圆心横坐标*/int centerX;/*** 圆心纵坐标*/int centerY;/*** 画笔宽度*/int paintWidth;public RoundProgressbar(Context context) {
//        super(context);this(context, null);}public RoundProgressbar(Context context, AttributeSet attrs) {
//        super(context, attrs);this(context, attrs, 0);}public RoundProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();rectF = new RectF();radius = dp2px(DEFAULT_RADIUS);paintWidth = dp2px(DEFAULT_STROKE_WIDTH);obtainStyledAttributes(context, attrs, defStyleAttr);}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int desiredWidth = radius * 2 + getPaddingLeft() + getPaddingRight();int desiredHeight = radius * 2 + getTop() + getBottom();int width;int height;if (widthMode == MeasureSpec.AT_MOST) {width = desiredWidth;} else {width = Math.max(widthSize, desiredWidth);}if (heightMode == MeasureSpec.AT_MOST) {height = desiredHeight;} else {height = Math.max(heightSize, desiredHeight);}setMeasuredDimension(width, height);}@Overrideprotected synchronized void onDraw(Canvas canvas) {
//        super.onDraw(canvas);int width = getWidth();int height = getHeight();int contentWidth = width - getPaddingLeft() - getPaddingRight();int contentHeight = height - getPaddingTop() - getPaddingBottom();// 设置圆心为画布正中心radius = contentWidth >= contentHeight ? contentHeight / 2 : contentWidth / 2;centerX = width / 2;centerY = height / 2;// 仅绘制边paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.BLUE);paint.setStrokeWidth(paintWidth);canvas.drawCircle(centerX, centerY, radius, paint);rectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);float ratio = getProgress() * 1.0f / getMax();int angle = (int) (ratio * 360);paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);canvas.drawArc(rectF, 0, angle, false, paint);}private void obtainStyledAttributes(Context context, AttributeSet attrs, int defStyleAttr) {TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundProgressbar, defStyleAttr, 0);int count = a.getIndexCount();for (int i = 0; i < count; i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.RoundProgressbar_strokeWidth:paintWidth = dp2px((int) a.getDimension(attr, DEFAULT_STROKE_WIDTH));break;}}a.recycle();}/*** dp 2 px** @param dpVal*/protected int dp2px(int dpVal) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal, getResources().getDisplayMetrics());}
}

属性文件:

<?xml version="1.0" encoding="utf-8"?>
<resources><attr name="strokeWidth" format="dimension" /><declare-styleable name="RoundProgressbar"><attr name="strokeWidth" /></declare-styleable></resources>

布局文件:

<com.zj.progressnumber.RoundProgressbarandroid:id="@+id/rpb"android:layout_width="300dp"android:layout_height="300dp"android:background="@android:color/holo_green_light"android:padding="20dp"android:progress="20"app:strokeWidth="1dp" />

这里写图片描述

实现:

这里写图片描述

增加文本

在圆中心增加文本显示

public class RoundProgressbar extends ProgressBar {public static final int DEFAULT_UNREACHED_COLOR = 0;public static final int DEFAULT_REACHED_COLOR = 0;public static final int DEFAULT_TEXT_COLOR = 0;// 设置默认圆大小,单位为 dppublic static final int DEFAULT_RADIUS = 60;// 设置默认画笔宽度,单位为 dppublic static final int DEFAULT_STROKE_WIDTH = 1;// 设置文字默认大小,单位为 sppublic static final int DEFAULT_TEXT_SIZE = 12;/*** 画笔*/private Paint paint;/*** 绘制圆弧时使用*/private RectF rectF;/*** 文字大小*/private Rect rect;/*** 圆半径*/int radius;/*** 圆心横坐标*/int centerX;/*** 圆心纵坐标*/int centerY;/*** 画笔宽度*/int paintWidth;/*** 文字大小*/int textSize;public RoundProgressbar(Context context) {
//        super(context);this(context, null);}public RoundProgressbar(Context context, AttributeSet attrs) {
//        super(context, attrs);this(context, attrs, 0);}public RoundProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();rectF = new RectF();rect = new Rect();radius = dp2px(DEFAULT_RADIUS);paintWidth = dp2px(DEFAULT_STROKE_WIDTH);textSize = sp2px(DEFAULT_TEXT_SIZE);obtainStyledAttributes(context, attrs, defStyleAttr);}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int desiredWidth = radius * 2 + getPaddingLeft() + getPaddingRight();int desiredHeight = radius * 2 + getTop() + getBottom();int width;int height;if (widthMode == MeasureSpec.AT_MOST) {width = desiredWidth;} else {width = Math.max(widthSize, desiredWidth);}if (heightMode == MeasureSpec.AT_MOST) {height = desiredHeight;} else {height = Math.max(heightSize, desiredHeight);}setMeasuredDimension(width, height);}@Overrideprotected synchronized void onDraw(Canvas canvas) {
//        super.onDraw(canvas);int width = getWidth();int height = getHeight();int contentWidth = width - getPaddingLeft() - getPaddingRight();int contentHeight = height - getPaddingTop() - getPaddingBottom();// 设置圆心为画布正中心radius = contentWidth >= contentHeight ? contentHeight / 2 : contentWidth / 2;centerX = width / 2;centerY = height / 2;// 仅绘制边paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.BLUE);paint.setStrokeWidth(paintWidth);canvas.drawCircle(centerX, centerY, radius, paint);rectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);float ratio = getProgress() * 1.0f / getMax();int angle = (int) (ratio * 360);paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);canvas.drawArc(rectF, 0, angle, false, paint);String text = getProgress() + "%";paint.setStyle(Paint.Style.FILL);paint.setTextSize(textSize);paint.getTextBounds(text, 0, text.length(), rect);int startX = centerX - rect.width() / 2;Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();int startY = (height - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;canvas.drawText(text, startX, startY, paint);}private void obtainStyledAttributes(Context context, AttributeSet attrs, int defStyleAttr) {TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundProgressbar, defStyleAttr, 0);int count = a.getIndexCount();for (int i = 0; i < count; i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.RoundProgressbar_strokeWidth:paintWidth = dp2px((int) a.getDimension(attr, DEFAULT_STROKE_WIDTH));break;case R.styleable.RoundProgressbar_textSize:textSize = sp2px((int) (a.getDimension(attr, DEFAULT_TEXT_SIZE)));break;}}a.recycle();}/*** 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());}
}

增加了自定义属性 - 文字大小:

<?xml version="1.0" encoding="utf-8"?>
<resources><attr name="textSize" format="dimension" /><attr name="strokeWidth" format="dimension" /><declare-styleable name="RoundProgressbar"><attr name="strokeWidth" /><attr name="textSize" /></declare-styleable></resources>

这里写图片描述

实现:

这里写图片描述

完善

目前,圆形进度条已实现进度显示和文本显示,下面增加自定义属性,可以自定义颜色

完整代码如下:

public class RoundProgressbar extends ProgressBar {public static final int DEFAULT_UNREACHED_COLOR = 0xFF6495ED;public static final int DEFAULT_REACHED_COLOR = 0xFFFF0000;public static final int DEFAULT_TEXT_COLOR = 0xFF0000CD;// 设置默认圆大小,单位为 dppublic static final int DEFAULT_RADIUS = 60;// 设置默认画笔宽度,单位为 dppublic static final int DEFAULT_STROKE_WIDTH = 1;// 设置文字默认大小,单位为 sppublic static final int DEFAULT_TEXT_SIZE = 12;private Paint paint;private RectF rectF;private Rect rect;int radius;int centerX;int centerY;int unreachedColor;int reachedColor;int textColor;int paintWidth;int textSize;public RoundProgressbar(Context context) {
//        super(context);this(context, null);}public RoundProgressbar(Context context, AttributeSet attrs) {
//        super(context, attrs);this(context, attrs, 0);}public RoundProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();rectF = new RectF();rect = new Rect();radius = dp2px(DEFAULT_RADIUS);paintWidth = dp2px(DEFAULT_STROKE_WIDTH);textSize = sp2px(DEFAULT_TEXT_SIZE);unreachedColor = DEFAULT_UNREACHED_COLOR;reachedColor = DEFAULT_REACHED_COLOR;textColor = DEFAULT_TEXT_COLOR;obtainStyledAttributes(context, attrs, defStyleAttr);}@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int desiredWidth = radius * 2 + getPaddingLeft() + getPaddingRight();int desiredHeight = radius * 2 + getTop() + getBottom();int width;int height;if (widthMode == MeasureSpec.AT_MOST) {width = desiredWidth;} else {width = Math.max(widthSize, desiredWidth);}if (heightMode == MeasureSpec.AT_MOST) {height = desiredHeight;} else {height = Math.max(heightSize, desiredHeight);}setMeasuredDimension(width, height);}@Overrideprotected synchronized void onDraw(Canvas canvas) {
//        super.onDraw(canvas);int width = getWidth();int height = getHeight();int contentWidth = width - getPaddingLeft() - getPaddingRight();int contentHeight = height - getPaddingTop() - getPaddingBottom();// 设置圆心为画布正中心radius = contentWidth >= contentHeight ? contentHeight / 2 : contentWidth / 2;centerX = width / 2;centerY = height / 2;// 仅绘制边paint.setStyle(Paint.Style.STROKE);paint.setColor(unreachedColor);paint.setStrokeWidth(paintWidth);canvas.drawCircle(centerX, centerY, radius, paint);rectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);float ratio = getProgress() * 1.0f / getMax();int angle = (int) (ratio * 360);paint.setColor(reachedColor);paint.setStyle(Paint.Style.STROKE);canvas.drawArc(rectF, 0, angle, false, paint);String text = getProgress() + "%";paint.setColor(textColor);paint.setStyle(Paint.Style.FILL);paint.setTextSize(textSize);paint.getTextBounds(text, 0, text.length(), rect);int startX = centerX - rect.width() / 2;Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();int startY = (height - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;canvas.drawText(text, startX, startY, paint);}private void obtainStyledAttributes(Context context, AttributeSet attrs, int defStyleAttr) {TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundProgressbar, defStyleAttr, 0);int count = a.getIndexCount();for (int i = 0; i < count; i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.RoundProgressbar_strokeWidth:paintWidth = dp2px((int) a.getDimension(attr, DEFAULT_STROKE_WIDTH));break;case R.styleable.RoundProgressbar_textSize:textSize = sp2px((int) (a.getDimension(attr, DEFAULT_TEXT_SIZE)));break;case R.styleable.RoundProgressbar_unreachedColor:unreachedColor = a.getColor(attr, DEFAULT_UNREACHED_COLOR);break;case R.styleable.RoundProgressbar_reachedColor:reachedColor = a.getColor(attr, DEFAULT_REACHED_COLOR);break;case R.styleable.RoundProgressbar_textColor:textColor = a.getColor(attr, DEFAULT_TEXT_COLOR);break;}}a.recycle();}/*** 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());}
}

资源文件:

<?xml version="1.0" encoding="utf-8"?>
<resources><attr name="reachedColor" format="color" /><attr name="unreachedColor" format="color" /><attr name="textSize" format="dimension" /><attr name="textColor" format="color" /><attr name="strokeWidth" format="dimension" /><declare-styleable name="RoundProgressbar"><attr name="strokeWidth" /><attr name="textSize" /><attr name="textColor" /><attr name="unreachedColor" /><attr name="reachedColor" /></declare-styleable></resources>

布局文件:

<com.zj.progressnumber.RoundProgressbarandroid:id="@+id/rpb"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@android:color/holo_green_light"android:padding="20dp"/>

这里写图片描述

实现:

这里写图片描述

这篇关于android 自定义 View(4)- 进度条(ProgressBar)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1081610

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使