Android Material Design风格自定义View1——弧形滚动百分比的圆形进度条

————自定义PercentProgressBar继承自View,五个自定义属性progressWidth(进度条宽度),progressBackColor(进度条背景色),progressFrontColor(进度条前景色),percentTextSize(百分比文字大小),percentTextColor(百分比文字颜色),可在布局文件中直接使用。

如需下载源码,请访问
https://github.com/fengchuanfang/PercentProgressBarDemo1

文章原创,转载请注明出处:
自定义Material Design风格带滚动百分比的圆形进度条

运行效果如下:


Android Material Design风格自定义View1——弧形滚动百分比的圆形进度条_第1张图片
percent_progress_bar_01.gif
Android Material Design风格自定义View1——弧形滚动百分比的圆形进度条_第2张图片
percent_progress_bar_02.gif

引入步骤

访问git地址下载源码,拷贝com.feng.edward.percentprogressbardemo1.view包下的PercentProgressBar类和attrs.xml中的PercentProgressBar的五项属性

或者新建java类PercentProgressBar,直接复制以下代码,再将attrs.xml中的代码放入项目对应attrs文件中。便可以在布局文件中直接使用。

package com.feng.edward.percentprogressbardemo1.view;

import com.feng.edward.percentprogressbardemo1.R;
import com.feng.edward.percentprogressbardemo1.util.DimensionUtils;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

/**
 * 功能描述:带滚动百分比的圆形进度条
 *
 * @author (作者) edward(冯丰枫)
 * @link http://www.jianshu.com/u/f7176d6d53d2
 * 创建时间: 2018/4/16 0016
 */
public class PercentProgressBar extends View {
    private Paint
            progressBackPaint, //进度条背景画笔
            progressFrontPaint,//进度条前景画笔
            percentTextPaint;  //百分比文字画笔

    private RectF
            progressRectF,//进度条圆弧所在的矩形
            percentTextRectF;//百分比文字所在的矩形

    private Path percentTextPath;   //百分比文字所在的路径
    private float percentTextRadius;  //百分比文字圆弧的半径
    private float progressPaintWidth; //进度条画笔的宽度

    private int percentProgress;//百分比进度(0 ~ 100)


    public PercentProgressBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PercentProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.PercentProgressBar, defStyleAttr, 0);

        //初始化进度条画笔的宽度
        progressPaintWidth = attributes.getDimension(R.styleable.PercentProgressBar_progressWidth, DimensionUtils.dip2px(context, 10));
        //初始化百分比文字的大小
        float percentTextPaintSize = attributes.getDimensionPixelSize(R.styleable.PercentProgressBar_percentTextSize, DimensionUtils.sp2px(context, 10));
        int progressBackColor = attributes.getColor(R.styleable.PercentProgressBar_progressBackColor, 0xffaaaaaa);
        int progressFrontColor = attributes.getColor(R.styleable.PercentProgressBar_progressFrontColor, 0xffFF4081);
        int percentTextColor = attributes.getColor(R.styleable.PercentProgressBar_percentTextColor, 0xffff0077);
        attributes.recycle();
        //初始化进度条背景画笔
        progressBackPaint = new Paint();
        progressBackPaint.setColor(progressBackColor);
        progressBackPaint.setStrokeWidth(progressPaintWidth);
        progressBackPaint.setAntiAlias(true);
        progressBackPaint.setStyle(Paint.Style.STROKE);

        //初始化进度条前景画笔
        progressFrontPaint = new Paint();
        progressFrontPaint.setColor(progressFrontColor);
        progressFrontPaint.setStrokeWidth(progressPaintWidth);
        progressFrontPaint.setAntiAlias(true);
        progressFrontPaint.setStyle(Paint.Style.STROKE);

        //初始化百分比文字画笔
        percentTextPaint = new Paint();
        percentTextPaint.setColor(percentTextColor);
        percentTextPaint.setTextSize(percentTextPaintSize);// 设置文字画笔的尺寸(px)
        percentTextPaint.setAntiAlias(true);
        percentTextPaint.setStyle(Paint.Style.STROKE);
        percentTextPaint.setTypeface(Typeface.DEFAULT_BOLD);

        //初始化百分比文字路径
        percentTextPath = new Path();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();// 获取控件的layout_width
        int height = getMeasuredHeight(); // 获取控件的layout_height
        //获取内切圆圆心坐标
        int centerX = width / 2;
        int centerY = height / 2;
        int radius = Math.min(width, height) / 2;//获取控件内切圆的半径

        Rect rect = new Rect();
        percentTextPaint.getTextBounds("100%", 0, "100%".length(), rect);//获取最大百分比文字的高度
        int textHeight = rect.height();
        //比较进度条的宽度和百分比文字的高度,去两者中较大者,用以计算进度条的半径,保证精度条和百分比文字互为中心
        float radiusArc = radius - (progressPaintWidth > textHeight ? progressPaintWidth / 2 : textHeight / 2);

        //初始化进度条圆弧所在的矩形
        progressRectF = new RectF();
        progressRectF.left = centerX - radiusArc;
        progressRectF.top = centerY - radiusArc;
        progressRectF.right = centerX + radiusArc;
        progressRectF.bottom = centerY + radiusArc;

        percentTextRadius = radiusArc - textHeight / 2;//计算百分比文字圆弧的半径

        //初始化百分比文字路径所在的矩形
        percentTextRectF = new RectF();
        percentTextRectF.left = centerX - percentTextRadius;
        percentTextRectF.top = centerY - percentTextRadius;
        percentTextRectF.right = centerX + percentTextRadius;
        percentTextRectF.bottom = centerY + percentTextRadius;

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制进度框的背景
        canvas.drawArc(progressRectF, 0, 360, false, progressBackPaint);
        //绘制进度框的前景(从圆形最高点中间,顺时针绘制)
        canvas.drawArc(progressRectF, -90, percentProgress / 100.0f * 360, false, progressFrontPaint);
        //百分比文字
        String text = percentProgress + "%";
        //计算百分比文字的弧跨度
        float sweepAngle = (float) (percentTextPaint.measureText(text) * 360 / (2 * Math.PI * percentTextRadius));
        //初始化百分比文字的弧路径
        percentTextPath.addArc(percentTextRectF, percentProgress * 3.6f - 90.0f - sweepAngle / 2.0f, sweepAngle);
        //绘制弧形百分比文字
        canvas.drawTextOnPath(text, percentTextPath, 0, 0, percentTextPaint);
        //路径重置
        percentTextPath.reset();
    }

    /**
     * 设置当前百分比进度
     */
    public void setPercentProgress(int percentProgress) {
        this.percentProgress = percentProgress;
        invalidate();
    }
}


attrs.xml



    
        
        
        
        
        
    

在布局文件dialog_layout.xml中使用如下:



    
    

如果想了解CircleImageView,请访问上篇文章史上最简洁高效的圆形ImageView

自定义进度条弹出框ProgressDialog,代码如下:

package com.feng.edward.percentprogressbardemo1.dialog;

import com.feng.edward.percentprogressbardemo1.R;
import com.feng.edward.percentprogressbardemo1.view.CircleImageView;
import com.feng.edward.percentprogressbardemo1.view.PercentProgressBar;

import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;

/**
 * 功能描述:
 *
 * @author (作者) edward(冯丰枫)
 * @link http://www.jianshu.com/u/f7176d6d53d2
 * 创建时间: 2018/4/17 0017
 */
public class ProgressDialog {
    private final Dialog mDialog;
    private final PercentProgressBar mPercentProgress;
    private final CircleImageView mCircleImageView;

    public ProgressDialog(Context context) {
        View view = LayoutInflater.from(context).inflate(R.layout.dialog_layout, null);
        mPercentProgress = view.findViewById(R.id.circle_percent_view);
        mCircleImageView = view.findViewById(R.id.circle_image_view);
        mDialog = new Dialog(context, R.style.ProgressDialogTheme);
        mDialog.setContentView(view);
        mDialog.setCanceledOnTouchOutside(true);
    }

    public void show() {
        mDialog.show();
    }

    public void setPercentProgress(int percentProgress) {
        mPercentProgress.setPercentProgress(percentProgress);
        mCircleImageView.setAlpha((float) percentProgress / 100);
    }

    public void dismiss() {
        mDialog.dismiss();
    }
}

在MainActivity中使用如下:

package com.feng.edward.percentprogressbardemo1;

import com.feng.edward.percentprogressbardemo1.dialog.ProgressDialog;
import com.feng.edward.percentprogressbardemo1.util.IPublishProgress;
import com.feng.edward.percentprogressbardemo1.util.MyAsyncTask;

import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements MyAsyncTask.IIsViewActive {
    private ProgressDialog mProgressDialog;
    private TextView mainText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mProgressDialog = new ProgressDialog(this);
        mainText = findViewById(R.id.main_text);
        mainText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mainText.setText(R.string.downloading);
                downLoad();
            }
        });
    }

    private void downLoad() {
        MyAsyncTask.newBuilder()
                .setPreExecute(new MyAsyncTask.IPreExecute() {
                    @Override
                    public void onPreExecute() {
                        mProgressDialog.show();
                    }
                })
                .setDoInBackground(new MyAsyncTask.IDoInBackground() {
                    @Override
                    public Void doInBackground(IPublishProgress publishProgress, Void... voids) {
                        try {
                            for (int i = 0; i <= 100; i++) {
                                Thread.sleep(100);
                                publishProgress.showProgress(i);
                            }
                        } catch (Exception ignore) {
                        }
                        return null;
                    }
                })
                .setProgressUpdate(new MyAsyncTask.IProgressUpdate() {
                    @Override
                    public void onProgressUpdate(Integer... values) {
                        mProgressDialog.setPercentProgress(values[0]);
                    }
                })
                .setViewActive(this)
                .setPostExecute(new MyAsyncTask.IPostExecute() {
                    @Override
                    public void onPostExecute(Void aVoid) {
                        mProgressDialog.dismiss();
                        mainText.setText(R.string.download_finish);
                    }
                })
                .start();
    }

    @Override
    public boolean isViewActive() {
        return !(isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed()));
    }


}

如想了解MyAsyncTask,请访问Android AsyncTask 优化封装

activity_mian.xml中的代码如下:




    

在布局文件中,设置百分比文字大小percentTextSize和进度条宽度progressWidth,可呈现以下两种不同的效果:


Android Material Design风格自定义View1——弧形滚动百分比的圆形进度条_第3张图片
percent_progress_bar_text_inside.jpg

对应属性为:

   app:percentTextSize="10sp"
            app:percentTextColor="#ff0000"
            app:progressWidth="12dp"
            app:progressFrontColor="#3F51B5"
            app:progressBackColor="#ffffff"
Android Material Design风格自定义View1——弧形滚动百分比的圆形进度条_第4张图片
percent_progress_bar_text_out.png

对应属性为:

          app:percentTextSize="10sp"
            app:percentTextColor="#ff0000"
            app:progressWidth="2dp"
            app:progressFrontColor="#3F51B5"
            app:progressBackColor="#ffffff"

你可能感兴趣的:(Android Material Design风格自定义View1——弧形滚动百分比的圆形进度条)