首先自定義屬性 res - values - attrs(自己建立):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCicle">
<!--畫筆的寬度-->
<attr name="progress_paint_width" format="dimension" />
<!--畫筆顔色-->
<attr name="progress_paint_color" format="color" />
<!--字型顔色-->
<attr name="progress_text_color" format="color" />
<!--字型尺寸-->
<attr name="progress_text_size" format="dimension" />
<!--加載進度的開始位置-->
<attr name="location" 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>
自定義布局類:
/**
* date:2018/11/22
* author:(家輝輝輝)
* function:圓形進度條
* 思路:
* 1.自定義屬性:文字的顔色和字型大小,圓弧的顔色和寬度,一開始加載進度的位置;
* 2.畫出需要的效果:畫圓弧,畫字型,使用畫筆paint在canvas上繪制;
* 3.設定進度,重新繪制;
* 4.接口回調。
*
*/
public class MyCicle extends View {
private int mCurrent;//目前進度
private Paint mPaintOut;
private Paint mPaintCurrent;
private Paint mPaintText;
private float mPaintWidth;//畫筆寬度
private int mPaintColor = Color.RED;//畫筆顔色
private int mTextColor = Color.BLACK;//字型顔色
private float mTextSize;//字型大小
private int location;//從哪個位置開始
private float startAngle;//開始角度
public MyCicle(Context context) {
this(context,null);
}
public MyCicle(Context context,AttributeSet attrs) {
this(context, attrs,0);
}
public MyCicle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化attrs.xml
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyCicle);
location = array.getInt(R.styleable.MyCicle_location, 1);
mPaintWidth = array.getDimension(R.styleable.MyCicle_progress_paint_width, dip2px(context, 4));//預設4dp
mPaintColor = array.getColor(R.styleable.MyCicle_progress_paint_color, mPaintColor);
mTextSize = array.getDimension(R.styleable.MyCicle_progress_text_size, dip2px(context, 18));//預設18sp
mTextColor = array.getColor(R.styleable.MyCicle_progress_text_color, mTextColor);
array.recycle();
//畫筆->背景圓弧
mPaintOut = new Paint();
mPaintOut.setAntiAlias(true);
mPaintOut.setStrokeWidth(mPaintWidth);
mPaintOut.setStyle(Paint.Style.STROKE);
mPaintOut.setColor(Color.GRAY);
mPaintOut.setStrokeCap(Paint.Cap.ROUND);
//畫筆->進度圓弧
mPaintCurrent = new Paint();
mPaintCurrent.setAntiAlias(true);
mPaintCurrent.setStrokeWidth(mPaintWidth);
mPaintCurrent.setStyle(Paint.Style.STROKE);
mPaintCurrent.setColor(mPaintColor);
mPaintCurrent.setStrokeCap(Paint.Cap.ROUND);
//畫筆->繪制字型
mPaintText = new Paint();
mPaintText.setAntiAlias(true);
mPaintText.setStyle(Paint.Style.FILL);
mPaintText.setColor(mTextColor);
mPaintText.setTextSize(mTextSize);
if (location == 1) {//預設從左側開始
startAngle = -180;
} else if (location == 2) {
startAngle = -90;
} else if (location == 3) {
startAngle = 0;
} else if (location == 4) {
startAngle = 90;
}
}
/**
* 根據手機的分辨率從 dp 的機關 轉成為 px(像素)
* */
private float dip2px(Context context, int dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = width > height ? height : width;
setMeasuredDimension(size, size);
}
@Override//繪制
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//繪制背景圓弧,因為畫筆有一定的寬度,所有畫圓弧的範圍要比View本身的大小稍微小一些,不然畫筆畫出來的東西會顯示不完整
RectF rectF = new RectF(mPaintWidth / 2, mPaintWidth / 2, getWidth() - mPaintWidth / 2, getHeight() - mPaintWidth / 2);
canvas.drawArc(rectF, 0, 360, false, mPaintOut);
//繪制目前進度
float sweepAngle = 360 * mCurrent / 100;
canvas.drawArc(rectF, startAngle, sweepAngle, false, mPaintCurrent);
//繪制進度數字
String text = mCurrent + "%";
//擷取文字寬度
float textWidth = mPaintText.measureText(text, 0, text.length());
float dx = getWidth() / 2 - textWidth / 2;
Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();
float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
float baseLine = getHeight() / 2 + dy;
canvas.drawText(text, dx, baseLine, mPaintText);
//判斷接口并調用接口
if (mLoadingCompleteListener != null && mCurrent == 100) {
mLoadingCompleteListener.complete();
}
}
/**
* 擷取目前進度值
*
* @return
*/
public int getmCurrent() {
return mCurrent;
}
/**
* 設定目前進度并重新繪制界面
*
* @param mCurrent
*/
public void setmCurrent(int mCurrent) {
this.mCurrent = mCurrent;
invalidate();
}
//建立接口
public interface OnLoadingCompleteListener {
void complete();
}
//聲明接口
private OnLoadingCompleteListener mLoadingCompleteListener;
//設定暴露方法
public void setOnLoadingCompleteListener(OnLoadingCompleteListener loadingCompleteListener) {
this.mLoadingCompleteListener = loadingCompleteListener;
}
}
MainActicity布局
<com.wjh.activity.myview.MyCicle
android:id="@+id/mycicle"
android:layout_width="150dp"
android:layout_height="150dp"
app:location="left"
app:progress_paint_color="#10c4f1"
app:progress_paint_width="4dp"
app:progress_text_color="#3F51B5"
app:progress_text_size="20sp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="55dp"/>
MainActivity代碼:
public class MainActivity extends AppCompatActivity {
private MyCicle mMyCicle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//找控件
mMyCicle = findViewById(R.id.mycicle);
//進度條從0到100
ValueAnimator animator = ValueAnimator.ofFloat(0, 100);
animator.setDuration(4000);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float current = (float) animation.getAnimatedValue();
mMyCicle.setmCurrent((int) current);
}
});
animator.start();
//使用接口回調
mMyCicle.setOnLoadingCompleteListener(new MyCicle.OnLoadingCompleteListener() {
@Override
public void complete() {
Toast.makeText(MainActivity.this, "加載完成", Toast.LENGTH_SHORT).show();
}
});
}
}
詳解檢視: https://www.jianshu.com/p/be71f6ffe512