如上 实现这种效果
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.Nullable;
public class EllipseView extends View {
private int mPadding = 10;//内边距基准值
private int mInnerCircleWidth = dp2px(140);//左右圆弧的距离 用于控制中间矩形的宽度大小
private int mViewWidth; // 控件宽度
private int mViewHeight; // 控件高度
private float mViewCenterX, mViewCenterY;
private float mCircleTopX, mCircleTopY;
private float mCircleBottomX, mCircleBottomY;
private int mRadius; // 内圆环的半径
private int progressWidth;//进度条宽度
private int progressIndex = 0;
private int currentProgress=0;//当前状态值
public EllipseView(Context context) {
this(context, null);
}
public EllipseView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public EllipseView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public EllipseView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private Paint mPaint;
private void init() {
progressWidth = dp2px(10);
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setPadding(dp2px(mPadding * 2), dp2px(mPadding), dp2px(mPadding * 2), dp2px(mPadding));
int widthMode = MeasureSpec.getMode(widthMeasureSpec);//从约束规范中获取模式
int widthSize = MeasureSpec.getSize(widthMeasureSpec);//从约束规范中获取尺寸
//在布局中设置了具体值
if (widthMode == MeasureSpec.EXACTLY)
mViewWidth = widthSize;
//在布局中设置 wrap_content,控件就取能完全展示内容的宽度(同时需要考虑屏幕的宽度)
if (widthMode == MeasureSpec.AT_MOST)
mViewWidth = Math.min(mViewWidth, widthSize);
//高度和宽度是2:1的关系
mViewHeight = mViewWidth * 2;
//保存测量宽度和测量高度
setMeasuredDimension(mViewWidth, mViewHeight);
mRadius = mViewWidth / 2;
mViewCenterX = mViewWidth / 2;
mViewCenterY = mViewHeight / 2;
//下圆弧圆心
mCircleTopX = mViewCenterX;
mCircleTopY = mViewCenterY + mInnerCircleWidth / 2f + mRadius / 4;
//上圆弧圆心
mCircleBottomX = mViewCenterX;
mCircleBottomY = mViewCenterY - mInnerCircleWidth / 2f - mRadius / 4;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.STROKE);//充满
mPaint.setColor(getResources().getColor(R.color.color_16CEFC));
mPaint.setStrokeWidth(progressWidth);
//画上圆环
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY + mRadius - progressWidth / 2,
180, 180, false, mPaint);
//画左边线
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
//画右边线
canvas.drawLine(mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY,
mPaint);
//画下圆环
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleTopX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
0,
180,
false,
mPaint);
mPaint.setColor(getResources().getColor(R.color.color_326BF7));
mPaint.setStrokeCap(Paint.Cap.ROUND);
//蠢办法 画各个区间的路径 从上圆中间逆时针开始 最终上圆中间结束
if(currentProgress <= 12.5) {
//逆时针画上左圆
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY + mRadius - progressWidth / 2,
269, -currentProgress * 7.2f, false, mPaint);
} else if (currentProgress > 12.5 & currentProgress <= 37.5) {
//左边线 从上往下
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
(float) (mCircleBottomY + (currentProgress - 12.5) * ((mCircleTopY - mCircleBottomY) / 25)),
mPaint);
} else if (currentProgress > 37.5 & currentProgress <= 62.5) {
//底部半圆
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
180, (float) -((currentProgress - 37.5) * 7.2f), false, mPaint);
} else if (currentProgress > 62.5 & currentProgress <= 87.5) {
//右边线 从下往上
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
180, -(25 * 7.2f), false, mPaint);
canvas.drawLine(mCircleTopX + mRadius - progressWidth / 2,
mCircleTopY,
mCircleBottomX + mRadius - progressWidth / 2,
(float) (mCircleTopY - (currentProgress - 62.5) * ((mCircleTopY - mCircleBottomY) / 25)),
mPaint);
} else if (currentProgress > 87.5 & currentProgress <= 100) {
//上半右边圆
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
180, -(25 * 7.2f), false, mPaint);
canvas.drawLine(mCircleTopX + mRadius - progressWidth / 2,
mCircleTopY,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY,
mPaint);
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY + mRadius - progressWidth / 2,
0, (float) -((currentProgress - 87.5) * 7.2f), false, mPaint);
}
drawMyPro(canvas);
}
//蠢办法 慢慢算各个部分的绘画值
private void drawMyPro(Canvas canvas) {
if(currentProgress<progressIndex){
if (progressIndex <= 12.5) {
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY + mRadius - progressWidth / 2,
(float) (269-currentProgress*7.2), -(progressIndex-currentProgress)* 7.2f, false, mPaint);
} else if (progressIndex > 12.5 & progressIndex <= 37.5) {
/* canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);*/
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
(float) (mCircleBottomY+ (currentProgress - 12.5) * ((mCircleTopY - mCircleBottomY) / 25)),
mCircleTopX - mRadius + progressWidth / 2,
(float) (mCircleBottomY + (progressIndex - 12.5) * ((mCircleTopY - mCircleBottomY) / 25)),
mPaint);
} else if (progressIndex > 37.5 & progressIndex <= 62.5) {
/* canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);*/
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
(float) (180-(currentProgress-37.5)*7.2)
, (float) -((progressIndex-currentProgress) * 7.2f), false, mPaint);
} else if (progressIndex > 62.5 & progressIndex <= 87.5) {
/* canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
180, -(25 * 7.2f), false, mPaint);*/
canvas.drawLine(mCircleTopX + mRadius - progressWidth / 2,
(float) (mCircleTopY- (currentProgress - 62.5) * ((mCircleTopY - mCircleBottomY) / 25)),
mCircleBottomX + mRadius - progressWidth / 2,
(float) (mCircleTopY - (progressIndex - 62.5) * ((mCircleTopY - mCircleBottomY) / 25)),
mPaint);
} else if (progressIndex > 87.5 & progressIndex <= 100) {
/* canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
180, -(25 * 7.2f), false, mPaint);
canvas.drawLine(mCircleTopX + mRadius - progressWidth / 2,
mCircleTopY,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY,
mPaint);*/
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY + mRadius - progressWidth / 2,
(float) (360-(currentProgress-87.5)*7.2), (float) -((progressIndex-currentProgress) * 7.2f), false, mPaint);
}
}
/*if (progressIndex <= 12.5) {
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY + mRadius - progressWidth / 2,
269, -progressIndex * 7.2f, false, mPaint);
} else if (progressIndex > 12.5 & progressIndex <= 37.5) {
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
(float) (mCircleBottomY + (progressIndex - 12.5) * ((mCircleTopY - mCircleBottomY) / 25)),
mPaint);
} else if (progressIndex > 37.5 & progressIndex <= 62.5) {
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
180, (float) -((progressIndex - 37.5) * 7.2f), false, mPaint);
} else if (progressIndex > 62.5 & progressIndex <= 87.5) {
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
180, -(25 * 7.2f), false, mPaint);
canvas.drawLine(mCircleTopX + mRadius - progressWidth / 2,
mCircleTopY,
mCircleBottomX + mRadius - progressWidth / 2,
(float) (mCircleTopY - (progressIndex - 62.5) * ((mCircleTopY - mCircleBottomY) / 25)),
mPaint);
} else if (progressIndex > 87.5 & progressIndex <= 100) {
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2, mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2, mCircleBottomY + mRadius - progressWidth / 2,
269, (float) (-12.5 * 7.2f), false, mPaint);
canvas.drawLine(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY,
mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY,
mPaint);
canvas.drawArc(mCircleTopX - mRadius + progressWidth / 2,
mCircleTopY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleTopY + mRadius - progressWidth / 2,
180, -(25 * 7.2f), false, mPaint);
canvas.drawLine(mCircleTopX + mRadius - progressWidth / 2,
mCircleTopY,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY,
mPaint);
canvas.drawArc(mCircleBottomX - mRadius + progressWidth / 2,
mCircleBottomY - mRadius + progressWidth / 2,
mCircleBottomX + mRadius - progressWidth / 2,
mCircleBottomY + mRadius - progressWidth / 2,
0, (float) -((progressIndex - 87.5) * 7.2f), false, mPaint);
}
*/
currentProgress=progressIndex;
}
//给控件设置进度
public void setProgress(int progress) {
if (progress < 0 || progress > 100) return;
progressIndex = progress;
postInvalidate();
}
private boolean isAnimFinish = true;
public void setProgressWithAnim(final int mprogress) {
if (mprogress < 0 || mprogress > 100 || !isAnimFinish) {
return;
}
ValueAnimator va = ValueAnimator.ofInt(currentProgress, mprogress);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int p = (int) animation.getAnimatedValue();
setProgress(p);
}
});
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
isAnimFinish = false;
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isAnimFinish = true;
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
isAnimFinish = true;
}
});
va.setDuration(1200);
va.start();
}
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
Resources.getSystem().getDisplayMetrics());
}
}
xml布局文件直接引入
<EllipseView
android:id="@+id/ellipseView"
android:layout_width="200dp"
android:layout_height="400dp"
/>
动态赋值
ellipseView.setProgressWithAnim(progress);//progress为进度值