1.首先在values里设置下自定义控件的属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RingProgress">
<!--画笔宽度-->
<attr name="progress_width" format="dimension"/>
<!--画笔颜色-->
<attr name="progress_start_color" format="color"/>
<attr name="progress_end_color" format="color"/>
<!--加载进度起始位置-->
<attr name="progress_start" format="enum">
<enum name="left" value="1"/>
<enum name="top" value="2"/>
<enum name="right" value="3"/>
<enum name="bottom" value="4"/>
</attr>
</declare-styleable>
</resources>
2.自定义控件的代码(里面注释很详细了)
package com.example.administrator.shoottest.view;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import com.example.administrator.shoottest.R;
/**
* Created by Administrator on 2019/2/18.
*/
public class RingProgress extends View {
private int mCurrent;//当前进度
private Paint mBgPaint;//背景paint
private Paint mProgressPaint;//进度paint
private float mProgressWidth;//进度条宽度
private int mProgressColor = Color.RED;
private int mProgressEndColor = Color.BLUE;
private int locationStart;//起始位置
private float startAngle;//开始角度
private ValueAnimator valueAnimator;
public RingProgress(Context context) {
this(context, null);
}
public RingProgress(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public RingProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet set) {
TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.RingProgress);
locationStart = typedArray.getInt(R.styleable.RingProgress_progress_start, 1);
mProgressColor = typedArray.getColor(R.styleable.RingProgress_progress_start_color, mProgressColor);
mProgressEndColor = typedArray.getColor(R.styleable.RingProgress_progress_end_color, mProgressEndColor);
mProgressWidth = typedArray.getDimension(R.styleable.RingProgress_progress_width, dp2px(context, 4));
typedArray.recycle();
//背景圆弧
mBgPaint = new Paint();
mBgPaint.setAntiAlias(true);
mBgPaint.setStrokeWidth(mProgressWidth);
mBgPaint.setStyle(Paint.Style.STROKE);
mBgPaint.setColor(Color.parseColor("#eaecf0"));
mBgPaint.setStrokeCap(Paint.Cap.ROUND);
//进度圆弧
mProgressPaint = new Paint();
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStrokeWidth(mProgressWidth);
mProgressPaint.setStyle(Paint.Style.STROKE);//空心圆(绘制描边)
switch (locationStart) {
case 1:
startAngle = -180;
break;
case 2:
startAngle = -90;
break;
case 3:
startAngle = 0;
break;
case 4:
startAngle = 90;
break;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = width < height ? width : height;
setMeasuredDimension(size, size);//正方形
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制背景圆弧
RectF rectF = new RectF(mProgressWidth / 2, mProgressWidth / 2, getWidth() - mProgressWidth / 2
, getHeight() - mProgressWidth / 2);
canvas.drawArc(rectF, 0, 360, false, mBgPaint);
//绘制当前进度
float sweepAngle = 360 * mCurrent / 100;
//绘制进度圆弧,颜色是渐变的所以圆弧也要一点一点的绘制
for (int i = 0; i < sweepAngle; i++) {
Integer color = (Integer) evaluate(i / sweepAngle, mProgressColor, mProgressEndColor);
mProgressPaint.setColor(color);
canvas.drawArc(rectF, startAngle + i, 1.35f, false, mProgressPaint);
}
}
private int getCurrent() {
return mCurrent;
}
//设置进度
private void setCurrent(int current) {
mCurrent = current;
invalidate();
}
private int tCurrent = -1;//初始进度
//动画
public void startAnimProgress(int current, int duation) {
valueAnimator = ValueAnimator.ofInt(0, current);
valueAnimator.setDuration(duation);
valueAnimator.setInterpolator(new LinearInterpolator());//加速效果 线性均匀改变
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int current = (int) animation.getAnimatedValue();
if (tCurrent != current) {
tCurrent = current;
setCurrent(current);
if (mOnAnimProgressListener != null) {
mOnAnimProgressListener.valueUpdate(current);
}
}
}
});
valueAnimator.start();
}
public interface OnAnimProgressListener {
void valueUpdate(int progress);
}
private OnAnimProgressListener mOnAnimProgressListener;
public void setOnAnimProgressListener(OnAnimProgressListener onAnimProgressListener) {
mOnAnimProgressListener = onAnimProgressListener;
}
public void destroy() {
if (valueAnimator != null) {
valueAnimator.cancel();
}
}
public static int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 从ArgbEvaluator类 copy出来的颜色渐变的方法
*
* @param fraction
* @param startValue
* @param endValue
* @return
*/
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
float startA = ((startInt >> 24) & 0xff) / 255.0f;
float startR = ((startInt >> 16) & 0xff) / 255.0f;
float startG = ((startInt >> 8) & 0xff) / 255.0f;
float startB = (startInt & 0xff) / 255.0f;
int endInt = (Integer) endValue;
float endA = ((endInt >> 24) & 0xff) / 255.0f;
float endR = ((endInt >> 16) & 0xff) / 255.0f;
float endG = ((endInt >> 8) & 0xff) / 255.0f;
float endB = (endInt & 0xff) / 255.0f;
// convert from sRGB to linear
startR = (float) Math.pow(startR, 2.2);
startG = (float) Math.pow(startG, 2.2);
startB = (float) Math.pow(startB, 2.2);
endR = (float) Math.pow(endR, 2.2);
endG = (float) Math.pow(endG, 2.2);
endB = (float) Math.pow(endB, 2.2);
// compute the interpolated color in linear space
float a = startA + fraction * (endA - startA);
float r = startR + fraction * (endR - startR);
float g = startG + fraction * (endG - startG);
float b = startB + fraction * (endB - startB);
// convert back to sRGB in the [0..255] range
a = a * 255.0f;
r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;
return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
}
}
3.测试代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context="com.example.administrator.shoottest.MainActivity">
<com.example.administrator.shoottest.view.RingProgress
android:layout_width="100dp"
android:layout_height="100dp"
app:progress_width="2dp"
android:id="@+id/ringProgress"
app:progress_start_color="@color/colorAccent"
app:progress_end_color="@color/colorPrimary"
app:progress_start="top"
/>
</RelativeLayout>
package com.example.administrator.shoottest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.example.administrator.shoottest.view.RingProgress;
public class MainActivity extends AppCompatActivity {
private RingProgress progress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progress=findViewById(R.id.ringProgress);
progress.startAnimProgress(30,1000);
}
}
做这个自定义控件颜色渐变的时候最开始想用SweepGradient扫描渐变的效果,但是发现这个扫描渐变只能从0度角开始,很是不方便。
后来发现了神奇的ArgbEvaluator颜色渐变的工具类,里面就一个方法,为了适配老机型,把方法copy出来自己用。