Android仿MIUI手机管家分数值进度条
效果图:

这个也是一个进度条,之前在MIUI9上的手机管家上看到,效果是一段弧度,中间一个百分比文字。
完整代码
自定义属性
Java代码
public class CircleProgressWithTextView extends View {/*** 默认值*//*** 默认的当前进度,默认为0*/private static final int DEFAULT_PROGRESS = 0;/*** 默认的最大值,默认为100*/private static final int DEFAULT_MAX = 100;/*** 默认进度圆弧颜色*/private final int DEFAULT_CIRCLE_COLOR = Color.parseColor("#0AA4A2");/*** 圆弧颜色*/private final int DEFAULT_REMAIN_CIRCLE_COLOR = Color.parseColor("#EFEFF0");/*** 默认背景颜色*/private final int DEFAULT_BG_COLOR = Color.parseColor("#00000000");/*** 默认文字颜色*/private final int DEFAULT_TEXT_COLOR = Color.parseColor("#0AA4A2");/*** 是否显示进度百分比文字*/private static final boolean DEFAULT_TEXT_ENABLE = true;/*** 绘制相关*/private RectF mRect;private Paint mCirclePaint;private Paint mTextPaint;private Paint mPercentPaint;/*** 画笔颜色*/private int mCircleColor;private int mRemainCircleColor;private int mTextColor;private int mBgColor;/*** 圆弧宽度*/private float mCircleBorderWidth;/*** View相关尺寸*/private int mWidth;private int mHeight;/*** 外圆半径*/private float mRadius;/*** 当前进度*/private float mProgress;/*** 进度最大值*/private int mMax;/*** 是否显示百分比文字*/private boolean mEnableText;/*** 弧线的开始角度,默认是0,是水平的,我们要从上面开始画*/private float mStartAngle = -90f;/*** 中心点X、Y坐标*/private int mCenterX;private int mCenterY;/*** 进度条进度*/private ValueAnimator mProgressAnimator;private OnProgressUpdateListener mProgressUpdateListener;public CircleProgressWithTextView(Context context) {super(context);init(null);}public CircleProgressWithTextView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init(attrs);}public CircleProgressWithTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(attrs);}/*** 初始化自定义属性*/private void initAttributeVar(AttributeSet attrs) {//默认圆弧宽度int defaultCircleBorderWidth = dip2px(getContext(), 5f);if (attrs != null) {TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.CircleProgressWithTextView);mProgress = array.getInt(R.styleable.CircleProgressWithTextView_cpt_progress, DEFAULT_PROGRESS);mMax = array.getInt(R.styleable.CircleProgressWithTextView_cpt_max, DEFAULT_MAX);//Xml设置的进度圆弧颜色mCircleColor = array.getColor(R.styleable.CircleProgressWithTextView_cpt_circle_color, DEFAULT_CIRCLE_COLOR);//Xml设置的圆弧颜色mRemainCircleColor = array.getColor(R.styleable.CircleProgressWithTextView_cpt_remain_circle_color, DEFAULT_REMAIN_CIRCLE_COLOR);//文字颜色mTextColor = array.getColor(R.styleable.CircleProgressWithTextView_cpt_text_color, DEFAULT_CIRCLE_COLOR);//读取设置的圆弧轮廓宽度,读取dimensionmCircleBorderWidth = array.getDimensionPixelSize(R.styleable.CircleProgressWithTextView_cpt_remain_circle_border_width, defaultCircleBorderWidth);//是否显示进度百分比文字mEnableText = array.getBoolean(R.styleable.CircleProgressWithTextView_cpt_text_enable, DEFAULT_TEXT_ENABLE);//背景颜色mBgColor = array.getColor(R.styleable.CircleProgressWithTextView_cpt_bg_color, DEFAULT_BG_COLOR);array.recycle();} else {//没有在Xml中设置属性,使用默认属性mProgress = DEFAULT_PROGRESS;mMax = DEFAULT_MAX;mCircleColor = DEFAULT_CIRCLE_COLOR;mRemainCircleColor = DEFAULT_REMAIN_CIRCLE_COLOR;mTextColor = DEFAULT_TEXT_COLOR;mCircleBorderWidth = defaultCircleBorderWidth;mEnableText = DEFAULT_TEXT_ENABLE;}}private void init(AttributeSet attrs) {initAttributeVar(attrs);//外圆画笔mCirclePaint = new Paint();mCirclePaint.setColor(mCircleColor);mCirclePaint.setStrokeWidth(mCircleBorderWidth);mCirclePaint.setStyle(Paint.Style.STROKE);//设置笔触为圆角mCirclePaint.setStrokeCap(Paint.Cap.ROUND);mCirclePaint.setAntiAlias(true);//文字画笔mTextPaint = new Paint();mTextPaint.setColor(mTextColor);mTextPaint.setStrokeWidth(dip2px(getContext(), 1f));mTextPaint.setStyle(Paint.Style.FILL);mTextPaint.setTextSize(sp2px(getContext(), 17f));mTextPaint.setAntiAlias(true);//百分比画笔mPercentPaint = new Paint();mPercentPaint.setColor(mTextColor);mPercentPaint.setStrokeWidth(dip2px(getContext(), 1f));mPercentPaint.setStyle(Paint.Style.FILL);mPercentPaint.setTextSize(sp2px(getContext(), 13f));mPercentPaint.setAntiAlias(true);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//控件的总宽高mWidth = w;mHeight = h;//取出padding值int paddingLeft = getPaddingLeft();int paddingRight = getPaddingRight();int paddingTop = getPaddingTop();int paddingBottom = getPaddingBottom();//绘制范围mRect = new RectF();mRect.left = (float) paddingLeft;mRect.top = (float) paddingTop;mRect.right = (float) mWidth - paddingRight;mRect.bottom = (float) mHeight - paddingBottom;//计算直径和半径float diameter = (Math.min(mWidth, mHeight)) - paddingLeft - paddingRight;mRadius = (float) ((diameter / 2) * 0.98);//计算圆心的坐标mCenterX = mWidth / 2;mCenterY = mHeight / 2;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(measureSpec(widthMeasureSpec), measureSpec(heightMeasureSpec));}private int measureSpec(int measureSpec) {int result;int mode = MeasureSpec.getMode(measureSpec);int size = MeasureSpec.getSize(measureSpec);//默认大小int defaultSize = dip2px(getContext(), 55f);//指定宽高则直接返回if (mode == MeasureSpec.EXACTLY) {result = size;} else if (mode == MeasureSpec.AT_MOST) {//wrap_content的情况result = Math.min(defaultSize, size);} else {//未指定,则使用默认的大小result = defaultSize;}return result;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.scale(0.93f, 0.93f, mCenterX, mCenterY);drawBg(canvas);float curProgress = getProgress();//画圆弧drawCircle(canvas, curProgress);if (mEnableText) {//画文字String progressText = String.valueOf((int) curProgress);drawProgressText(canvas, progressText);}}/*** 画背景*/private void drawBg(Canvas canvas) {canvas.drawColor(mBgColor);}/*** 画圆弧*/private void drawCircle(Canvas canvas, float curProgress) {mCirclePaint.setColor(mRemainCircleColor);canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);//绘制当前进度的弧线mCirclePaint.setColor(mCircleColor);float angle = 360 * (curProgress * 1.0f / getMax());canvas.drawArc(mRect, mStartAngle, angle, false, mCirclePaint);//绘制剩下的度数的弧线//float remainAngle = 360f - angle;//mCirclePaint.setColor(mRemainCircleColor);//canvas.drawArc(mRect, mStartAngle + angle, remainAngle, false, mCirclePaint);}/*** 画进度文字*/private void drawProgressText(Canvas canvas, String progressText) {Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();float baseLine = -(fontMetrics.ascent + fontMetrics.descent) / 2;float textWidth = mTextPaint.measureText(progressText);float startX = mCenterX - (textWidth / 2);float endY = mCenterY + baseLine;canvas.drawText(progressText, startX, endY, mTextPaint);//画百分比String percentText = "%";//计算百分比文字的起始X坐标float percentStartX = 0;if (progressText.length() == 1) {percentStartX = mCenterX + dip2px(getContext(), 5f);} else if (progressText.length() == 2) {percentStartX = mCenterX + dip2px(getContext(), 10f);}//百分比文字Y坐标,中心点Y坐标,和数值文字的Y坐标一样float percentEndY = mCenterY + baseLine;canvas.drawText(percentText, percentStartX, percentEndY, mPercentPaint);}/*** 指定时间,开始进度** @param preProgress 之前的进度* @param duration 执行时间*/public void startProgressByTime(int preProgress, long duration) {if (mProgressAnimator == null) {mProgressAnimator = ValueAnimator.ofInt(preProgress, mMax);}mProgressAnimator.setInterpolator(new LinearInterpolator());mProgressAnimator.setDuration(duration);mProgressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {Integer cValue = (Integer) animation.getAnimatedValue();setProgress(cValue);if (mProgressUpdateListener != null) {mProgressUpdateListener.onProgressUpdate(cValue);}}});mProgressAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);if (mProgressUpdateListener != null) {mProgressUpdateListener.onStart();}}@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);//结束,设置回0setProgress(0);if (mProgressUpdateListener != null) {mProgressUpdateListener.onEnd();}}});mProgressAnimator.start();}/*** 进度更新监听*/public interface OnProgressUpdateListener {void onStart();/*** 进度更新** @param curProgress 当前进度*/void onProgressUpdate(int curProgress);void onEnd();}public static class OnProgressUpdateAdapter implements OnProgressUpdateListener {@Overridepublic void onStart() {}@Overridepublic void onProgressUpdate(int curProgress) {}@Overridepublic void onEnd() {}}public void setOnProgressUpdateListener(OnProgressUpdateListener progressUpdateListener) {mProgressUpdateListener = progressUpdateListener;}public float getProgress() {return mProgress;}public void setProgress(float mProgress) {this.mProgress = mProgress;postInvalidate();}public float getMax() {return mMax;}public void setMax(int max) {this.mMax = max;postInvalidate();}public static int dip2px(Context context, float dipValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}public static int px2dp(Context context, float pxValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}private int sp2px(Context context, float spVal) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,spVal, context.getResources().getDisplayMetrics());}}
示例代码
Xml布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.hzh.circle.progress.sample.MainActivity"><com.hzh.circle.progress.sample.widget.CircleProgressWithTextViewandroid:id="@+id/circleProgress"android:layout_width="100dp"android:layout_height="100dp"android:layout_centerInParent="true"android:paddingLeft="10dp"android:paddingTop="10dp"android:paddingRight="10dp"android:paddingBottom="10dp"app:cpt_circle_color="#0AA4A2"app:cpt_text_color="#0AA4A2"app:cpt_max="100"app:cpt_progress="30"app:cpt_remain_circle_border_width="3dp"app:cpt_remain_circle_color="#EFEFF0"app:cpt_text_enable="true" />RelativeLayout>
Java代码
public class MainActivity extends AppCompatActivity {protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final CircleProgressWithTextView circleProgress = findViewById(R.id.circleProgress);//使用值动画,不断更新进度ValueAnimator animator = ValueAnimator.ofFloat(0, 100);animator.setInterpolator(new LinearInterpolator());animator.setRepeatCount(ValueAnimator.INFINITE);animator.setRepeatMode(ValueAnimator.RESTART);animator.setDuration(3000);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {Float cValue = (Float) animation.getAnimatedValue();circleProgress.setProgress(cValue);}});animator.start();}}
需要源码的童鞋公众号【龙旋】对话框回复关键字:miui,即可获得。
到这里就结束啦。
评论
