第一步 :自定义view
/**
-
Created by TU on 2019/11/19.
*/
public class ArcProgressBar extends View {
private int diameter = 500; //直径
private float centerX; //圆心X坐标
private float centerY; //圆心Y坐标private Paint allArcPaint;//整个弧形画笔
private Paint progressPaint;//当前进度的弧形画笔
private Paint vTextPaint; //内容显示文字画笔
private Paint hintPaint; //显示单位文字画笔
private Paint degreePaint;//外部刻度线
private Paint curSpeedPaint;//显示标题文字private RectF bgRect;//弧形矩阵区域
private ValueAnimator progressAnimator;//执行进度动画
private PaintFlagsDrawFilter mDrawFilter;//用于抗锯齿
private SweepGradient sweepGradient;//梯度渲染,用于渐变
private Matrix rotateMatrix;//渐变矩阵private float startAngle = 135;//起始角度
private float sweepAngle = 270;//最大角度
private float currentAngle = 0;//当前进度角度
private float lastAngle;//进度变化时最终角度
private int[] colors = new int[]{Color.GREEN, Color.YELLOW, Color.RED};//进度渐变三色(左到右渐变)
private float maxValues = 60;//默认进度最大值
private float curValues = 0;//默认进度变化值
private float bgArcWidth = dipToPx(2);//背景进度宽度
private int bgArcColor;//背景进度颜色
private float progressWidth = dipToPx(10);//进度宽度
private float textSize = dipToPx(60);//默认字体大小
private float hintSize = dipToPx(15);
private float curSpeedSize = dipToPx(13);
private int aniSpeed = 1000;//默认动画时长
private float longdegree = dipToPx(13);//刻度长
private float shortdegree = dipToPx(5);//刻度短
private final int DEGREE_PROGRESS_DISTANCE = dipToPx(8);private static final class ColorConfig {
private static String HINT_COLOR = “#676767”;
private static String LONG_DEGREE_COLOR = “#000000”;
private static String SHORT_DEGREE_COLOR = “#000000”;
}private boolean isShowCurrentSpeed = true;
private String titleString;//标题文字
private String hintString;//内容单位文字//是否需要标题文字描述等
private boolean isNeedTitle;
private boolean isNeedUnit;
private boolean isNeedDial;
private boolean isNeedContent;// 最大角度和最大进度值
private float kValue;public ArcProgressBar(Context context) {
super(context, null);
initView();
}public ArcProgressBar(Context context, AttributeSet attrs) {
super(context, attrs, 0);
initCofig(context, attrs);
initView();
}public ArcProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initCofig(context, attrs);
initView();
}/**
-
初始化布局配置
*/
private void initCofig(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ArcProgressBar);
int color1 = a.getColor(R.styleable.ArcProgressBar_front_color1, Color.GREEN);
int color2 = a.getColor(R.styleable.ArcProgressBar_front_color2, color1);
int color3 = a.getColor(R.styleable.ArcProgressBar_front_color3, color1);
colors = new int[]{color1, color2, color3, color3};sweepAngle = a.getInteger(R.styleable.ArcProgressBar_total_engle, 270);
bgArcWidth = a.getDimension(R.styleable.ArcProgressBar_back_width, dipToPx(2));
bgArcColor = a.getColor(R.styleable.ArcProgressBar_back_color, Color.BLACK);
progressWidth = a.getDimension(R.styleable.ArcProgressBar_front_width, dipToPx(10));
isNeedTitle = a.getBoolean(R.styleable.ArcProgressBar_is_need_title, false);
isNeedContent = a.getBoolean(R.styleable.ArcProgressBar_is_need_content, false);
isNeedUnit = a.getBoolean(R.styleable.ArcProgressBar_is_need_unit, false);
isNeedDial = a.getBoolean(R.styleable.ArcProgressBar_is_need_dial, false);
hintString = a.getString(R.styleable.ArcProgressBar_string_unit);
titleString = a.getString(R.styleable.ArcProgressBar_string_title);
curValues = a.getFloat(R.styleable.ArcProgressBar_current_value, 0);
maxValues = a.getFloat(R.styleable.ArcProgressBar_max_value, 60);
aniSpeed = a.getInteger(R.styleable.ArcProgressBar_ani_speed, 1000);
setCurrentValues(curValues);
setMaxValues(maxValues);
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = (int) (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE);
int height = (int) (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE);
setMeasuredDimension(width, height);
}private void initView() {
diameter = 3 * getScreenWidth() / 5;
//弧形的矩阵区域
bgRect = new RectF();
bgRect.top = longdegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE;
bgRect.left = longdegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE;
bgRect.right = diameter + (longdegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE);
bgRect.bottom = diameter + (longdegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE);//圆心 centerX = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE) / 2; centerY = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE) / 2; //外部刻度线 degreePaint = new Paint(); degreePaint.setColor(Color.parseColor(ColorConfig.LONG_DEGREE_COLOR)); //整个弧形 allArcPaint = new Paint(); allArcPaint.setAntiAlias(true); allArcPaint.setStyle(Paint.Style.STROKE); allArcPaint.setStrokeWidth(bgArcWidth); allArcPaint.setColor(bgArcColor); allArcPaint.setStrokeCap(Paint.Cap.ROUND); //当前进度的弧形 progressPaint = new Paint(); progressPaint.setAntiAlias(true); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeCap(Paint.Cap.ROUND); progressPaint.setStrokeWidth(progressWidth); progressPaint.setColor(Color.GREEN); //内容显示文字 vTextPaint = new Paint(); vTextPaint.setTextSize(textSize); vTextPaint.setColor(Color.BLACK); vTextPaint.setTextAlign(Paint.Align.CENTER); //显示单位文字 hintPaint = new Paint(); hintPaint.setTextSize(hintSize); hintPaint.setColor(Color.parseColor(ColorConfig.HINT_COLOR)); hintPaint.setTextAlign(Paint.Align.CENTER); //显示标题文字 curSpeedPaint = new Paint(); curSpeedPaint.setTextSize(curSpeedSize); curSpeedPaint.setColor(Color.parseColor(ColorConfig.HINT_COLOR)); curSpeedPaint.setTextAlign(Paint.Align.CENTER); //抗锯齿,渐变渲染,矩阵 mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); sweepGradient = new SweepGradient(centerX, centerY, colors, null); rotateMatrix = new Matrix();
}
@SuppressLint(“DefaultLocale”)
@Override
protected void onDraw(Canvas canvas) {
//抗锯齿
canvas.setDrawFilter(mDrawFilter);if (isNeedDial) { //画刻度线 for (int i = 0; i < 40; i++) { if (i > 15 && i < 25) { canvas.rotate(9, centerX, centerY); continue; } if (i % 5 == 0) { degreePaint.setStrokeWidth(dipToPx(2)); degreePaint.setColor(Color.parseColor(ColorConfig.LONG_DEGREE_COLOR)); canvas.drawLine(centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE, centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - longdegree, degreePaint); } else { degreePaint.setStrokeWidth(dipToPx(1.4f)); degreePaint.setColor(Color.parseColor(ColorConfig.SHORT_DEGREE_COLOR)); canvas.drawLine(centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longdegree - shortdegree) / 2, centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longdegree - shortdegree) / 2 - shortdegree, degreePaint); } canvas.rotate(9, centerX, centerY); } } //整个弧 canvas.drawArc(bgRect, startAngle, sweepAngle, false, allArcPaint); //设置渐变色 rotateMatrix.setRotate(130, centerX, centerY); sweepGradient.setLocalMatrix(rotateMatrix); progressPaint.setShader(sweepGradient); //当前进度 canvas.drawArc(bgRect, startAngle, currentAngle, false, progressPaint); if (isNeedContent) { canvas.drawText(String.format("%.0f", curValues), centerX, centerY + textSize / 3, vTextPaint); } if (isNeedUnit) { canvas.drawText(hintString, centerX, centerY + 2 * textSize / 3, hintPaint); } if (isNeedTitle) { canvas.drawText(titleString, centerX, centerY - 2 * textSize / 3, curSpeedPaint); } invalidate();
}
/**
- 设置最大值
- @param maxValues
*/
public void setMaxValues(float maxValues) {
this.maxValues = maxValues;
kValue = sweepAngle / maxValues;
}
/**
- 设置动画时长
- @param aniSpeed
*/
public void setAniSpeed(int aniSpeed) {
this.aniSpeed = aniSpeed;
}
/**
- 设置当前值
- @param currentValues
*/
public void setCurrentValues(float currentValues) {
if (currentValues > maxValues) {
currentValues = maxValues;
}
if (currentValues < 0) {
currentValues = 0;
}
this.curValues = currentValues;
lastAngle = currentAngle;
setAnimation(lastAngle, currentValues * kValue, aniSpeed);
}
/**
- 设置整个圆弧宽度
- @param bgArcWidth
*/
public void setBgArcWidth(int bgArcWidth) {
this.bgArcWidth = bgArcWidth;
}
/**
- 设置进度宽度
- @param progressWidth
*/
public void setProgressWidth(int progressWidth) {
this.progressWidth = progressWidth;
}
/**
- 设置速度文字大小
- @param textSize
*/
public void setTextSize(int textSize) {
this.textSize = textSize;
}
/**
- 设置单位文字大小
- @param hintSize
*/
public void setHintSize(int hintSize) {
this.hintSize = hintSize;
}
/**
- 设置单位文字
- @param hintString
*/
public void setUnit(String hintString) {
this.hintString = hintString;
invalidate();
}
/**
- 设置直径大小
- @param diameter
*/
public void setDiameter(int diameter) {
this.diameter = dipToPx(diameter);
}
/**
- 设置标题
- @param title
*/
private void setTitle(String title) {
this.titleString = title;
}
/**
- 设置是否显示标题
- @param isNeedTitle
*/
private void setIsNeedTitle(boolean isNeedTitle) {
this.isNeedTitle = isNeedTitle;
}
/**
- 设置是否显示单位文字
- @param isNeedUnit
*/
private void setIsNeedUnit(boolean isNeedUnit) {
this.isNeedUnit = isNeedUnit;
}
/**
- 设置是否显示外部刻度盘
- @param isNeedDial
*/
private void setIsNeedDial(boolean isNeedDial) {
this.isNeedDial = isNeedDial;
}
/**
- 为进度设置动画
- @param last
- @param current
*/
private void setAnimation(float last, float current, int length) {
progressAnimator = ValueAnimator.ofFloat(last, current);
progressAnimator.setDuration(length);
progressAnimator.setTarget(currentAngle);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentAngle = (float) animation.getAnimatedValue();
curValues = currentAngle / kValue;
}
});
progressAnimator.start();
}
/**
- dip 转换成px
- @param dip
- @return
*/
private int dipToPx(float dip) {
float density = getContext().getResources().getDisplayMetrics().density;
return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1));
}
/**
- 得到屏幕宽度
- @return
*/
private int getScreenWidth() {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
}
attrs.xml
-
<attr name="current_value" format="float" />
<attr name="max_value" format="float" />
<attr name="total_engle" format="integer" />
<attr name="ani_speed" format="integer" />
<attr name="string_title" format="string" />
<attr name="string_unit" format="string" />
<attr name="is_need_title" format="boolean" />
<attr name="is_need_content" format="boolean" />
<attr name="is_need_unit" format="boolean" />
<attr name="is_need_dial" format="boolean" />
第二步 :XML引用
<com.zkzj.android_commer.util.ArcProgressBar
android:id="@+id/progress_arc"
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:layout_below="@+id/iv_head"
app:back_color="#EE5A5A"
android:layout_centerInParent=“true”
app:current_value=“0”
app:front_color1="@color/colorAccent"
app:front_color2="@color/colorPrimary"
app:front_color3="@color/colorPrimaryDark"
app:front_width="@dimen/qb_px_4"
app:is_need_content=“true”
app:is_need_dial=“true”
app:is_need_unit=“true”
app:max_value=“100”
app:string_title="@string/app_name"
app:string_unit=“This is unit”
app:total_engle=“270”
/>
第三步 :Activity调用
runOnUiThread(new Runnable() {
@Override
public void run() {
//时长
mProgressArc.setAniSpeed(3000);
//模拟动态进度
for (int i = 0; i < 106; i++) {
mProgressArc.setCurrentValues(i);
}
}
});
最后,文章很短,路还漫长,希望大伙喜欢这篇文章,我们下期再见。