Android-仿微信旋轉(zhuǎn)圓弧進度條

記得舊版本Android微信版本,加載圖片時,會有一個無限圓弧轉(zhuǎn)動Loading效果,但是現(xiàn)在去掉了,之前仿寫過一次,現(xiàn)在將代碼分享出來,如果大家需要可以拿去用~

原理分析

后續(xù)補

完整代碼

  • Java代碼
public class RotateCircleProgressBar extends View {
    /**
     * View寬高
     */
    private int mWidth;
    private int mHeight;
    /**
     * 畫筆
     */
    private Paint mCircleBorderPaint;
    private Paint mArcPaint;
    /**
     * 外圓顏色
     */
    private int mCircleColor = Color.parseColor("#4DEFEFF0");
    /**
     * 弧線顏色
     */
    private int mArcColor = Color.parseColor("#FFFFFF");
    /**
     * 中心點X、Y坐標(biāo)
     */
    private int mCenterX;
    private int mCenterY;
    /**
     * 圓半徑
     */
    private float mRadius;
    /**
     * 旋轉(zhuǎn)角度
     */
    private float mAngle;
    /**
     * 繪制范圍
     */
    private RectF mRect;

    public RotateCircleProgressBar(Context context) {
        super(context);
        init();
    }

    public RotateCircleProgressBar(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RotateCircleProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        //外圓畫筆
        mCircleBorderPaint = new Paint();
        mCircleBorderPaint.setStyle(Paint.Style.STROKE);
        mCircleBorderPaint.setColor(mCircleColor);
        mCircleBorderPaint.setStrokeWidth(dip2px(getContext(), 4f));
        mCircleBorderPaint.setAntiAlias(true);
        //弧線畫筆
        mArcPaint = new Paint();
        mArcPaint.setStyle(Paint.Style.STROKE);
        mArcPaint.setColor(mArcColor);
        mArcPaint.setStrokeWidth(dip2px(getContext(), 3.5f));
        mArcPaint.setAntiAlias(true);
        //設(shè)置筆觸為圓形
        mArcPaint.setStrokeCap(Paint.Cap.ROUND);

        ValueAnimator animator = ValueAnimator.ofFloat(0, 360);
        animator.setInterpolator(new LinearInterpolator());
        animator.setDuration(600);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //更新旋轉(zhuǎn)角度
                mAngle = (Float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.start();
    }

    @Override
    protected 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);
        //計算圓心的坐標(biāo)
        mCenterX = mWidth / 2;
        mCenterY = mHeight / 2;
    }

    @Override
    protected 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(), 30f);
        //指定寬高則直接返回
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else if (mode == MeasureSpec.AT_MOST) {
            //wrap_content的情況
            result = Math.min(defaultSize, size);
        } else {//未指定,則使用默認的大小
            result = defaultSize;
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.scale(0.87f, 0.87f, mCenterX, mCenterY);
        //讓畫布旋轉(zhuǎn)指定角度
        canvas.rotate(mAngle, mCenterX, mCenterY);
        //畫外圓
        canvas.drawCircle(mCenterX, mCenterY, mRadius, mCircleBorderPaint);
        //畫弧線
        canvas.drawArc(mRect, -90f, 200f, false, mArcPaint);
    }

    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());
    }
}

布局代碼

由于是無限進度的不斷旋轉(zhuǎn),所以只需要布局里面引入,后面做顯示、隱藏即可,大家記得拷貝完控件后,布局里面全包名要改成自己的。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="#000000"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hzh.rotate.circle.MainActivity">

    <com.hzh.rotate.circle.widget.RotateCircleProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />
</RelativeLayout>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容