android 自定义 View(4)- 进度条(ProgressBar)
来源:互联网 发布:2017知乎用户调查报告 编辑:程序博客网 时间:2024/05/01 02:16
参考:
Android 打造形形色色的进度条 实现可以如此简单
daimajia/NumberProgressBar
自定义视图(View
)是 Android
开发的一个进阶内容。随着开发的深入,肯定会出现系统提供的基础控件不符合需求的情况。一方面通过组合基础控件以形成新的布局,另一方面可以通过自定义控件的方式来更加灵活的实现需求
自定义视图涉及到 Android
系统许多方面的内容,下面根据自己的理解顺序来讲一讲如何自定义视图
主要内容
- 进度条浅析
- 水平进度条
- 文本进度条
- 圆形进度条
参考: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; } @Override protected 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.SimpleProgressbar 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" /></android.support.design.widget.CoordinatorLayout>
每隔 500
毫秒增加进度条进度,实现如下:
public class MainActivity extends AppCompatActivity { @Override protected 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() { @Override public 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.SimpleProgressbar android: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"; @Override protected 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() { @Override public 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; // 进度条默认高,单位为 dp public static final int DEFAULT_LINE_HEIGHT = 2; // 进度条默认宽,单位为 dp public 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); } @Override protected 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); } @Override protected 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%"; // 进度条默认高,单位为 dp public static final int DEFAULT_LINE_HEIGHT = 2; // 进度条默认宽,单位为 dp public static final int DEFAULT_LINE_WIDTH = 100; // 文本大小,单位为 sp public 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(); } @Override protected 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.ZProgressbar android: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%"; // 进度条默认高,单位为 dp public static final int DEFAULT_LINE_HEIGHT = 2; // 进度条默认宽,单位为 dp public static final int DEFAULT_LINE_WIDTH = 100; // 文本大小,单位为 sp public 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); } @Override protected 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); } @Override protected 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%"; // 进度条默认高,单位为 dp public static final int DEFAULT_LINE_HEIGHT = 2; // 进度条默认宽,单位为 dp public static final int DEFAULT_LINE_WIDTH = 100; // 文本大小,单位为 sp public 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); } @Override protected 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); } @Override protected 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.SimpleProgressbar android: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.ZProgressbar android: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"; @Override protected 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() { @Override public 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(); } @Override protected 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.RoundProgressbar android: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 { // 设置默认圆大小,单位为 dp public static final int DEFAULT_RADIUS = 30; // 设置默认画笔宽度,单位为 dp public 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); } @Override protected 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); } @Override protected 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.RoundProgressbar android: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; // 设置默认圆大小,单位为 dp public static final int DEFAULT_RADIUS = 60; // 设置默认画笔宽度,单位为 dp public static final int DEFAULT_STROKE_WIDTH = 1; // 设置文字默认大小,单位为 sp public 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); } @Override protected 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); } @Override protected 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; // 设置默认圆大小,单位为 dp public static final int DEFAULT_RADIUS = 60; // 设置默认画笔宽度,单位为 dp public static final int DEFAULT_STROKE_WIDTH = 1; // 设置文字默认大小,单位为 sp public 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); } @Override protected 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); } @Override protected 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.RoundProgressbar android: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)
- 自定义View之-ProgressBar进度条
- Android自定义View(ProgressBar)
- Android自定义进度条(ProgressBar)的问题
- 自定义progressBar(进度条)
- 自定义进度条(ProgressBar)
- android ProgressBar 自定义进度条颜色
- android ProgressBar 实现自定义进度条
- Android 各种自定义进度条Progressbar
- Android开发高级技术自定义进度条(自定义progressbar)
- Android 自定义View (三) ProgressBar
- android 纯java代码实现自定义进度条(ProgressBar)
- android 自定义 ProgressBar (类似微博拍摄视频进度条)
- Android自定义控件继承View,进度条ProgressBar,<layer-list><shap>的使用
- #小美化#android 自定义进度条ProgressBar
- Androidの自定义进度条ProgressBar实现
- Android ProgressBar高级自定义水平/圆形进度条
- Android学习之自定义进度条ProgressBar
- Oracle初识笔记(一)
- 书籍截图
- 游戏产品的创新
- Python3基础-元组
- Android实现异步任务机制AsyncTask 的使用及源码分析
- android 自定义 View(4)- 进度条(ProgressBar)
- BST(线索二叉树实现)
- Servlet学习
- 代码混淆详解
- iOS开发
- Activity工作过程源码分析
- NDK的使用(java调用C方法)
- 滑动表层div时阻止底层div滑动
- 关于JavaScript的splice 和slice 方法小结