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

相关文章

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

Android实现打开本地pdf文件的两种方式

《Android实现打开本地pdf文件的两种方式》在现代应用中,PDF格式因其跨平台、稳定性好、展示内容一致等特点,在Android平台上,如何高效地打开本地PDF文件,不仅关系到用户体验,也直接影响... 目录一、项目概述二、相关知识2.1 PDF文件基本概述2.2 android 文件访问与存储权限2.

Android Studio 配置国内镜像源的实现步骤

《AndroidStudio配置国内镜像源的实现步骤》本文主要介绍了AndroidStudio配置国内镜像源的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、修改 hosts,解决 SDK 下载失败的问题二、修改 gradle 地址,解决 gradle

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现