精通Android自定义View(十九)自定义圆形炫彩加载转圈效果

1 效果

2 源码 


public class JiondongView extends View {
    private Paint mBackgroundPaint;
    private float mScaledDensity;
    //背景的宽与高
    private int mBgWidth;
    private int mBgHeight;

    //屏幕的宽与高
    private int mMeasureWidth=0;
    private int mMeasureHeight=0;

    //圆角
    private int mBgRx;
    private int mBgRy;
    private RectF mBgRectF;

    //误差
    private int flag;
    private Paint mTextdPaint;
    private String mMsgText="!";
    private float mMsgTextLength;
    private float mMsgTextHeight;
    private Paint mCirclPaint;
    private Paint mCirclRingPaint;
    //默认view的宽度
    private int mDefaultWidth = dp2px(100);
    private int mDefaultHeight =mDefaultWidth;


    private float mCirclRingRoateAle=0;
    private ValueAnimator mValueAnimator;

    public JiondongView(Context context) {
        super(context);
        init(context,null,0);
    }

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

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

    private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr){


        mValueAnimator = ValueAnimator.ofFloat(0,1f);
        mValueAnimator.setDuration(380);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mCirclRingRoateAle=360*((Float)valueAnimator.getAnimatedValue());
                Log.e("loadingviw","loading");
                invalidate();
            }
        });
        mValueAnimator.setRepeatCount(10000);
        mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
        mValueAnimator.setInterpolator(new LinearInterpolator());
        //屏幕密度缩放比例
        mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity;

        //背景
        mBackgroundPaint = new Paint();
        mBackgroundPaint.setAntiAlias(true);
        mBackgroundPaint.setDither(true);
        mBackgroundPaint.setStyle(Paint.Style.FILL);
        mBackgroundPaint.setColor(Color.parseColor("#bb2A2A2A"));

        //圆
        mCirclPaint = new Paint();
        mCirclPaint.setAntiAlias(true);
        mCirclPaint.setDither(true);
        mCirclPaint.setStyle(Paint.Style.FILL);
        mCirclPaint.setColor(Color.parseColor("#ffffff"));

        //环
        mCirclRingPaint = new Paint();
        mCirclRingPaint.setAntiAlias(true);
        mCirclRingPaint.setDither(true);
        mCirclRingPaint.setStyle(Paint.Style.STROKE);
        mCirclRingPaint.setStrokeWidth(2.6f*mScaledDensity);
        mCirclRingPaint.setColor(Color.parseColor("#ffcc00"));

        mBgWidth = (int) (60*mScaledDensity);
        mBgHeight = (int) (60*mScaledDensity);
        mBgRx= (int) (8*mScaledDensity);
        mBgRy= (int) (8*mScaledDensity);

        flag= (int) (16*mScaledDensity);


        mTextdPaint = new Paint();
        mTextdPaint.setAntiAlias(true);
        mTextdPaint.setDither(true);
        mTextdPaint.setTextSize(20*mScaledDensity);
        mTextdPaint.setStyle(Paint.Style.STROKE);
        mTextdPaint.setColor(Color.parseColor("#000000"));




    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //测量计算宽度
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        if (widthSpecMode == MeasureSpec.EXACTLY) {
            //当specMode = EXACTLY时,精确值模式,即当我们在布局文件中为View指定了具体的大小
            mMeasureWidth = widthSpecSize;
        } else {
            //指定默认大小
            mMeasureWidth = mDefaultWidth;
            if (widthSpecMode == MeasureSpec.AT_MOST) {
                mMeasureWidth = Math.min(mMeasureWidth, widthSpecSize);
            }
        }

        //测量计算View的高
        int heightSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        if (heightSpecMode == MeasureSpec.EXACTLY) {
            //当specMode = EXACTLY时,精确值模式,即当我们在布局文件中为View指定了具体的大小
            mMeasureHeight = heightSpecSize;
        } else {
            //指定默认大小
            mMeasureHeight = mDefaultHeight;
            if (heightSpecMode == MeasureSpec.AT_MOST) {
                mMeasureHeight = Math.min(mMeasureHeight, heightSpecSize);
            }
        }
        mMeasureHeight=mMeasureHeight-getPaddingBottom()-getPaddingTop();
        mMeasureWidth=mMeasureWidth-getPaddingLeft()-getPaddingBottom();
        //重新测量
        setMeasuredDimension(mMeasureWidth, mMeasureHeight);
    }

    //onSizeChanged() 在控件大小发生改变时调用。所以这里初始化会被调用一次
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);


        mBgRectF = new RectF( -mBgWidth / 2, - mBgHeight / 2,  mBgWidth/2, mBgHeight/2);
        mMsgTextLength = mTextdPaint.measureText(mMsgText);
        //文字的y轴坐标
        Paint.FontMetrics fontMetrics = mTextdPaint.getFontMetrics();
        mMsgTextHeight = (Math.abs(fontMetrics.ascent) - fontMetrics.descent) / 2;
        int[] mMinColors = {Color.YELLOW, Color.GREEN, Color.WHITE, Color.YELLOW};
        //先创建一个渲染器
        SweepGradient mSweepGradient = new SweepGradient(0,
                0, //以圆弧中心作为扫描渲染的中心以便实现需要的效果
                mMinColors, //这是我定义好的颜色数组,包含2个颜色:#35C3D7、#2894DD
                null);
        //把渐变设置到笔刷
        mCirclRingPaint.setShader(mSweepGradient);



    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        canvas.translate(mMeasureWidth/2,mMeasureHeight/2);

        if (mBgRectF != null) {
            canvas.drawRoundRect(mBgRectF,mBgRx,mBgRy,mBackgroundPaint);
        }

        canvas.drawCircle(0,0,mBgWidth*0.4f,mCirclPaint);

        canvas.drawText(mMsgText,-mMsgTextLength/2,mMsgTextHeight,mTextdPaint);


        canvas.rotate(mCirclRingRoateAle);

        canvas.drawCircle(0,0,mBgWidth*0.34f,mCirclRingPaint);
    }

    //将设置的db转为屏幕像素
    protected int dp2px(int dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, getResources().getDisplayMetrics());
    }


    public void start(){
        mValueAnimator.start();
    }


    public void close(){
        if (mValueAnimator != null) {
            mValueAnimator.cancel();
        }
    }
    public boolean isStart() {
        return mValueAnimator.isRunning();
    }
}

3 SweepGradient  渲染器 《精通Android自定义View(六)绘制篇Paint分析

SweepGradient 颜色渲染器,用来实现颜色的过渡

 

早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页