preface

Since see big god “fan blowing leaves” custom control, is based on Gif to do. I see interesting GIFs and wonder how to do that. So, let’s start with an easy one.

Nothing complicated. The center is a circle. There are three ripples that come out of the circle. The renderings are as follows.

Initialize the

Public class extends BaseView {// extends BaseView private int mRadius = displayUtils.dp2px (this.getContext(), 30); private int mFirstRip = DisplayUtils.dp2px(this.getContext(), 20); private int mSecondRip = DisplayUtils.dp2px(this.getContext(), 40); private int mThirdRip = DisplayUtils.dp2px(this.getContext(), 60); Private ValueAnimator mValueAnimator privatefloat mAnimationValue;

    public RippleView(Context context) {
        this(context, null);
    }

    public RippleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RippleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint.setStrokeWidth(DisplayUtils.dp2px(this.getContext(), 1));
        mValueAnimator = ValueAnimator.ofFloat(0, 1).setDuration(1000);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimationValue = (float) animation.getAnimatedValue(); postInvalidate(); }}); mValueAnimator.setRepeatCount(-1); mValueAnimator.start(); }Copy the code

Measure View size

View size = inner circle diameter + final position of maximum wave + Margin + padding


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int measuredWidth = width, measuredHeight = height;
        if(widthMode ! = MeasureSpec.EXACTLY) { measuredWidth = mRadius * 2 + mThirdRip * 2 + mMargin * 2 + mPadding * 2; }if(heightMode ! = MeasureSpec.EXACTLY) { measuredHeight = mRadius * 2 + mThirdRip * 2 + mMargin * 2 + mPadding * 2; }setMeasuredDimension(measuredWidth, measuredHeight);
    }
Copy the code

draw

Draw the inner circle, three waves. Waves are evaluated according to mAnimationValue.


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mViewWidth / 2, mViewHeight / 2);
        canvas.save();
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawCircle(0, 0, mRadius, mPaint);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(0, 0, mRadius + mFirstRip * mAnimationValue, mPaint);
        canvas.drawCircle(0, 0, mRadius + mSecondRip * mAnimationValue, mPaint);
        canvas.drawCircle(0, 0, mRadius + mThirdRip * mAnimationValue, mPaint);
        postInvalidate();
        canvas.restore();
    }
Copy the code

Regulating the speed

The minimum speed is 1 and the maximum 100. Controlled by SeekBar. That’s it.

    public void setSpeed(int Speed) {long l = (long) (1000 * (1-(Speed * 1.0f) / 100f)); mValueAnimator.setDuration(l); } } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { mRippleView.setSpeed(progress); }Copy the code