自定义圆形的progressBar进阶——线程篇

自定义圆形的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开发。如果设计的思想有错误,欢迎提出错误。

posted @ 2020-11-09 18:17  wangheq  阅读(158)  评论(0编辑  收藏  举报