Android仿MIUI手機(jī)管家分?jǐn)?shù)值進(jìn)度條
效果圖:

這個(gè)也是一個(gè)進(jìn)度條,之前在MIUI9上的手機(jī)管家上看到,效果是一段弧度,中間一個(gè)百分比文字。
完整代碼
自定義屬性
Java代碼
public class CircleProgressWithTextView extends View {/*** 默認(rèn)值*//*** 默認(rèn)的當(dāng)前進(jìn)度,默認(rèn)為0*/private static final int DEFAULT_PROGRESS = 0;/*** 默認(rèn)的最大值,默認(rèn)為100*/private static final int DEFAULT_MAX = 100;/*** 默認(rèn)進(jìn)度圓弧顏色*/private final int DEFAULT_CIRCLE_COLOR = Color.parseColor("#0AA4A2");/*** 圓弧顏色*/private final int DEFAULT_REMAIN_CIRCLE_COLOR = Color.parseColor("#EFEFF0");/*** 默認(rèn)背景顏色*/private final int DEFAULT_BG_COLOR = Color.parseColor("#00000000");/*** 默認(rèn)文字顏色*/private final int DEFAULT_TEXT_COLOR = Color.parseColor("#0AA4A2");/*** 是否顯示進(jìn)度百分比文字*/private static final boolean DEFAULT_TEXT_ENABLE = true;/*** 繪制相關(guān)*/private RectF mRect;private Paint mCirclePaint;private Paint mTextPaint;private Paint mPercentPaint;/*** 畫(huà)筆顏色*/private int mCircleColor;private int mRemainCircleColor;private int mTextColor;private int mBgColor;/*** 圓弧寬度*/private float mCircleBorderWidth;/*** View相關(guān)尺寸*/private int mWidth;private int mHeight;/*** 外圓半徑*/private float mRadius;/*** 當(dāng)前進(jìn)度*/private float mProgress;/*** 進(jìn)度最大值*/private int mMax;/*** 是否顯示百分比文字*/private boolean mEnableText;/*** 弧線(xiàn)的開(kāi)始角度,默認(rèn)是0,是水平的,我們要從上面開(kāi)始畫(huà)*/private float mStartAngle = -90f;/*** 中心點(diǎn)X、Y坐標(biāo)*/private int mCenterX;private int mCenterY;/*** 進(jìn)度條進(jìn)度*/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) {//默認(rèn)圓弧寬度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設(shè)置的進(jìn)度圓弧顏色mCircleColor = array.getColor(R.styleable.CircleProgressWithTextView_cpt_circle_color, DEFAULT_CIRCLE_COLOR);//Xml設(shè)置的圓弧顏色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);//讀取設(shè)置的圓弧輪廓寬度,讀取dimensionmCircleBorderWidth = array.getDimensionPixelSize(R.styleable.CircleProgressWithTextView_cpt_remain_circle_border_width, defaultCircleBorderWidth);//是否顯示進(jìn)度百分比文字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 {//沒(méi)有在Xml中設(shè)置屬性,使用默認(rèn)屬性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);//外圓畫(huà)筆mCirclePaint = new Paint();mCirclePaint.setColor(mCircleColor);mCirclePaint.setStrokeWidth(mCircleBorderWidth);mCirclePaint.setStyle(Paint.Style.STROKE);//設(shè)置筆觸為圓角mCirclePaint.setStrokeCap(Paint.Cap.ROUND);mCirclePaint.setAntiAlias(true);//文字畫(huà)筆mTextPaint = new Paint();mTextPaint.setColor(mTextColor);mTextPaint.setStrokeWidth(dip2px(getContext(), 1f));mTextPaint.setStyle(Paint.Style.FILL);mTextPaint.setTextSize(sp2px(getContext(), 17f));mTextPaint.setAntiAlias(true);//百分比畫(huà)筆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;//計(jì)算直徑和半徑float diameter = (Math.min(mWidth, mHeight)) - paddingLeft - paddingRight;mRadius = (float) ((diameter / 2) * 0.98);//計(jì)算圓心的坐標(biāo)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);//默認(rèn)大小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 {//未指定,則使用默認(rèn)的大小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();//畫(huà)圓弧drawCircle(canvas, curProgress);if (mEnableText) {//畫(huà)文字String progressText = String.valueOf((int) curProgress);drawProgressText(canvas, progressText);}}/*** 畫(huà)背景*/private void drawBg(Canvas canvas) {canvas.drawColor(mBgColor);}/*** 畫(huà)圓弧*/private void drawCircle(Canvas canvas, float curProgress) {mCirclePaint.setColor(mRemainCircleColor);canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);//繪制當(dāng)前進(jìn)度的弧線(xiàn)mCirclePaint.setColor(mCircleColor);float angle = 360 * (curProgress * 1.0f / getMax());canvas.drawArc(mRect, mStartAngle, angle, false, mCirclePaint);//繪制剩下的度數(shù)的弧線(xiàn)//float remainAngle = 360f - angle;//mCirclePaint.setColor(mRemainCircleColor);//canvas.drawArc(mRect, mStartAngle + angle, remainAngle, false, mCirclePaint);}/*** 畫(huà)進(jìn)度文字*/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);//畫(huà)百分比String percentText = "%";//計(jì)算百分比文字的起始X坐標(biāo)float percentStartX = 0;if (progressText.length() == 1) {percentStartX = mCenterX + dip2px(getContext(), 5f);} else if (progressText.length() == 2) {percentStartX = mCenterX + dip2px(getContext(), 10f);}//百分比文字Y坐標(biāo),中心點(diǎn)Y坐標(biāo),和數(shù)值文字的Y坐標(biāo)一樣float percentEndY = mCenterY + baseLine;canvas.drawText(percentText, percentStartX, percentEndY, mPercentPaint);}/*** 指定時(shí)間,開(kāi)始進(jìn)度** @param preProgress 之前的進(jìn)度* @param duration 執(zhí)行時(shí)間*/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);//結(jié)束,設(shè)置回0setProgress(0);if (mProgressUpdateListener != null) {mProgressUpdateListener.onEnd();}}});mProgressAnimator.start();}/*** 進(jìn)度更新監(jiān)聽(tīng)*/public interface OnProgressUpdateListener {void onStart();/*** 進(jìn)度更新** @param curProgress 當(dāng)前進(jìn)度*/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);//使用值動(dòng)畫(huà),不斷更新進(jìn)度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();}}
需要源碼的童鞋公眾號(hào)【龍旋】對(duì)話(huà)框回復(fù)關(guān)鍵字:miui,即可獲得。
到這里就結(jié)束啦。
評(píng)論
圖片
表情
