自定义炫酷的progressBar进阶
上一篇教程讲解如何设计一个自定义的进度条,这篇主要结合线程来设计如何结合线程的思想使进度条自行跑动。比如我们开发的时候需要,开启子线程去下载东西或者实时的检测进度,并显示出来,这个时候就用到了线程。
一、自定义的圆形的progressBar
将上一篇的RoundnessProgressBar.java复制过来
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.View;
/**
* 自定义绚丽的ProgressBar.
*/
public class RoundnessProgressBar extends View {
/**
* 进度条所占用的角度
*/
private static final int ARC_FULL_DEGREE = 300;
//进度条个数
private static final int COUNT = 100;
//每个进度条所占用角度
private static final float ARC_EACH_PROGRESS = ARC_FULL_DEGREE * 1.0f / (COUNT - 1);
/**
* 弧线细线条的长度
*/
private int ARC_LINE_LENGTH;
/**
* 弧线细线条的宽度
*/
private int ARC_LINE_WIDTH;
/**
* 组件的宽,高
*/
private int width, height;
/**
* 进度条最大值和当前进度值
*/
private float max, progress;
/**
* 绘制弧线的画笔
*/
private Paint progressPaint;
/**
* 绘制文字的画笔
*/
private Paint textPaint;
/**
* 绘制文字背景圆形的画笔
*/
private Paint textBgPaint;
/**
* 圆弧的半径
*/
private int circleRadius;
/**
* 圆弧圆心位置
*/
private int centerX, centerY;
public RoundnessProgressBar(Context context) {
super(context);
init();
}
public RoundnessProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundnessProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
textBgPaint = new Paint();
textBgPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed){
width = getWidth();
height = getHeight();
//计算圆弧半径和圆心点
circleRadius = Math.min(width, height) / 2;
ARC_LINE_LENGTH = circleRadius / 6;
ARC_LINE_WIDTH = ARC_LINE_LENGTH / 8;
centerX = width / 2;
centerY = height / 2;
}
super.onLayout(changed, left, top, right, bottom);
}
private Rect textBounds = new Rect();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float start = (360 - ARC_FULL_DEGREE) >> 1; //进度条起始角度
float sweep1 = ARC_FULL_DEGREE * (progress / max); //进度划过的角度
//绘制进度条
progressPaint.setColor(Color.parseColor(calColor(progress / max, "#ffff0000", "#ff00ff00")));
progressPaint.setStrokeWidth(ARC_LINE_WIDTH);
float drawDegree = 1.6f;
while (drawDegree <= ARC_FULL_DEGREE) {
double a = (start + drawDegree) / 180 * Math.PI;
float lineStartX = centerX - circleRadius * (float) Math.sin(a);
float lineStartY = centerY + circleRadius * (float) Math.cos(a);
float lineStopX = lineStartX + ARC_LINE_LENGTH * (float) Math.sin(a);
float lineStopY = lineStartY - ARC_LINE_LENGTH * (float) Math.cos(a);
if (drawDegree > sweep1) {
//绘制进度条背景
progressPaint.setColor(Color.parseColor("#88aaaaaa"));
progressPaint.setStrokeWidth(ARC_LINE_WIDTH >> 1);
}
canvas.drawLine(lineStartX, lineStartY, lineStopX, lineStopY, progressPaint);
drawDegree += ARC_EACH_PROGRESS;
}
//绘制文字背景圆形
textBgPaint.setStyle(Paint.Style.FILL);//设置填充
textBgPaint.setColor(Color.parseColor("#41668b"));
canvas.drawCircle(centerX, centerY, (circleRadius - ARC_LINE_LENGTH) * 0.8f, textBgPaint);
textBgPaint.setStyle(Paint.Style.STROKE);//设置空心
textBgPaint.setStrokeWidth(2);
textBgPaint.setColor(Color.parseColor("#aaaaaaaa"));
canvas.drawCircle(centerX, centerY, (circleRadius - ARC_LINE_LENGTH) * 0.8f, textBgPaint);
//上一行文字
textPaint.setTextSize(circleRadius >> 1);
String text = (int) (100 * progress / max) + "";
float textLen = textPaint.measureText(text);
//计算文字高度
textPaint.getTextBounds("8", 0, 1, textBounds);
float h1 = textBounds.height();
canvas.drawText(text, centerX - textLen / 2, centerY - circleRadius / 10 + h1 / 2, textPaint);
//分
textPaint.setTextSize(circleRadius >> 3);
textPaint.getTextBounds("%", 0, 1, textBounds);
float h11 = textBounds.height();
canvas.drawText("%", centerX + textLen / 2 + 5, centerY - circleRadius / 10 + h1 / 2 - (h1 - h11), textPaint);
//下一行文字
textPaint.setTextSize(circleRadius / 6);
text = "检测进度";
textLen = textPaint.measureText(text);
canvas.drawText(text, centerX - textLen / 2, centerY + circleRadius / 2.5f, textPaint);
}
public void setMax(int max) {
this.max = max;
invalidate();
}
//动画切换进度值(异步)
public void setProgress(final float progress) {
new Thread(new Runnable() {
@Override
public void run() {
float oldProgress = RoundnessProgressBar.this.progress;
for (int i = 1; i <= 100; i++) {
RoundnessProgressBar.this.progress = oldProgress + (progress - oldProgress) * (1.0f * i / 100);
postInvalidate();
SystemClock.sleep(20);
}
}
}).start();
}
//直接设置进度值(同步)
public void setProgressSync(float progress) {
this.progress = progress;
invalidate();
}
/**
* 计算渐变效果中间的某个颜色值。
* 仅支持 #aarrggbb 模式,例如 #ccc9c9b2
*/
public String calColor(float fraction, String startValue, String endValue) {
int start_a, start_r, start_g, start_b;
int end_a, end_r, end_g, end_b;
//start
start_a = getIntValue(startValue, 1, 3);
start_r = getIntValue(startValue, 3, 5);
start_g = getIntValue(startValue, 5, 7);
start_b = getIntValue(startValue, 7, 9);
//end
end_a = getIntValue(endValue, 1, 3);
end_r = getIntValue(endValue, 3, 5);
end_g = getIntValue(endValue, 5, 7);
end_b = getIntValue(endValue, 7, 9);
return "#" + getHexString((int) (start_a + fraction * (end_a - start_a)))
+ getHexString((int) (start_r + fraction * (end_r - start_r)))
+ getHexString((int) (start_g + fraction * (end_g - start_g)))
+ getHexString((int) (start_b + fraction * (end_b - start_b)));
}
//从原始#AARRGGBB颜色值中指定位置截取,并转为int.
private int getIntValue(String hexValue, int start, int end) {
return Integer.parseInt(hexValue.substring(start, end), 16);
}
private String getHexString(int value) {
String a = Integer.toHexString(value);
if (a.length() == 1) {
a = "0" + a;
}
return a;
}
}
二、布局文件
新建一个布局文件activity_main.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:layout_gravity="center">
<com.example.progressbar.RoundnessProgressBar
android:id="@+id/circular_pb"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerHorizontal="true"
android:layout_gravity="center"
android:layout_marginTop="25dp"
android:layout_weight="0.43"
android:visibility="visible"
/>
<Button
android:id="@+id/button"
android:text="开启线程"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/circular_pb"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
这里将按钮设计为点击按钮后开启线程,在子线程对进度条进行加加。然后在将其显示出来。
三、MainActivity.java实现
然后再MainActivity.java文件中加载布局,使用线程,使用这个progressBar。子线程每隔1秒将进度条加1,然后显示出来。
public class MainActivity extends AppCompatActivity {
private RoundnessProgressBar pb;
public Handler handler = new Handler();
private int percent = 0;
Runnable runnable = new Runnable() {
@Override
public void run() {
pb.setProgressSync(percent);
try {
Thread.sleep(1000);
percent++;
// handler.post(runnable);
if (percent==100){//设置进度条最大值为100.如果跑到100就重新跑,这里重新跑的时候会有出错的现象
percent=0;
pb.setProgress(0);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
if (actionBar!=null){
actionBar.hide();
}
Button button = findViewById(R.id.button);
pb = findViewById(R.id.circular_pb);
pb.setMax(100);
pb.setProgress(0);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(){
@Override
public void run() {
super.run();
while (true){
handler.post(runnable);
pb.setProgressSync(percent);
}
}
}.start();
}
});
}
}
这样在这里就实现了使用子线程来自动的每隔一秒将进度条加一。这里就不附上具体的进度条的跑动视频了。
注:功能实现出来了,但是不清楚设计的线程对不对。自己也在正学Android开发。如果设计的思想有错误,欢迎提出错误。