This is the 22nd day of my participation in the August Wen Challenge.More challenges in August

Series of articles

Android custom View go animation (simplify complexity)


There is source code at the end of the article


preface

In the last article, I implemented simple dynamic effects. Assuming that this is a type of animation, can multiple effects be displayed in combination like animation in Android? This article will expand with two examples. The second example is a simplified version of go animation.


Android custom View using drawArc method to achieve dynamic effects

One, the implementation of the previous article

        mSweep += SWEEP_INC;
        if (mSweep > 360) {
            mSweep -= 360;
        }
        / / refresh the View
        invalidate();
Copy the code

Second, the first expansion (not optimized)

Effect:

Ideas:

1. In simple implementations, only one value is used to repeat the loop to achieve dynamic effects. In most cases, the animation is only shown once. It’s easy to make the dynamic effect happen only once: here it is.

  if (mSweep > 360) {
            //mSweep -= 360;
        }
Copy the code

As shown above, do not restore the modified value.

The key to this effect is to add a solid style brush

 mPaint1.setStyle(Paint.Style.FILL);
Copy the code

2. In order for the animation to be executed only once, a Boolean value is needed.

    private boolean viewContinue=true;
Copy the code

And the logical code becomes

    if (viewContinue==true){
            mSweep += SWEEP_INC;
            if (mSweep > 360) {
                mSweep1 += SWEEP_INC;
                if (mSweep1>360){
                  viewContinue=false; }}/ / refresh the View
            invalidate();
        }
Copy the code

Case Development:

  • You can give the user a way to execute the animation again by changing mSweep, mSweep1 to 0, and changing the viewContinue value to true.
  • Can be placed in an array to iterate through multiple effects.

Source code for this case

public class MySampleView extends View {
    private int mWidth;
    private int mHeight;
    private int useWidth, minwidth;
    private Paint mPaint,mPaint1;
    private Paint mFramePaint;
    private RectF mBigOval;
    private float mStart;
    private float mSweep ,mSweep1;
    private boolean viewContinue=true;

    private static final float SWEEP_INC = 2;

    public MySampleView(Context context) {
        super(context);
    }

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

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MySampleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    private void init(a) {
        initPaint();
    }
    private void initPaint(a) {
        / / initialization
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(0x88FF0000);
        mPaint.setStrokeWidth(4);

        mPaint1 = new Paint();
        mPaint1.setAntiAlias(true);
        mPaint1.setStyle(Paint.Style.FILL);
        mPaint1.setColor(0x88FF0000);
        / / initialization
        mFramePaint = new Paint();
        mFramePaint.setAntiAlias(true);
        mFramePaint.setStyle(Paint.Style.STROKE);
        mFramePaint.setStrokeWidth(0);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        useWidth = mWidth;
        if(mWidth > mHeight) { useWidth = mHeight; }} @Override
    protected void onDraw(Canvas canvas) {
        init();
        // Define a minimum identifier
        minwidth = useWidth / 10;
        mBigOval = new RectF(minwidth, minwidth, minwidth*9, minwidth*9);
        // Draw the background
        canvas.drawColor(Color.WHITE);
        canvas.drawRect(mBigOval, mFramePaint);
        canvas.drawArc(mBigOval, mStart, mSweep, true, mPaint);
        canvas.drawArc(mBigOval, mStart, mSweep1, true, mPaint1);

        if (viewContinue==true){
            mSweep += SWEEP_INC;
            if (mSweep > 360) {
                mSweep1 += SWEEP_INC;
                if (mSweep1>360){
                  viewContinue=false; }}/ / refresh the Viewinvalidate(); }}}Copy the code

Iii. The second case (emphasis of this paper)

I believe many friends have seen this article: Android custom view of go animation

The effect

The previous article was written so complex is to introduce some Android custom view some knowledge, but in fact, the implementation of a similar effect is extremely simple, so directly start.

1. Make a ball move in a straight line

Effect:

Ideas:

Change the position of the drawn ball with an offset.

Code:

Displacement is the offset

 mBigOval = new RectF(minwidth+displacement, minwidth, minwidth*2+displacement, minwidth*2);
        // Draw the background
        canvas.drawColor(Color.WHITE);
        //canvas.drawRect(mBigOval, mFramePaint);
        canvas.drawArc(mBigOval, 0.360.false, mPaint);


        if (viewContinue){
            displacement += SWEEP_INC;
            if (displacement > minwidth*7) {
              viewContinue=false;
            }
            / / refresh the View
            invalidate();
        }
Copy the code

2. Draw another ball moving in the opposite direction

Effect:

Code:

  mBigOval = new RectF(minwidth+displacement, minwidth, minwidth*2+displacement, minwidth*2);
        mBigOval1 = new RectF(minwidth*8-displacement, minwidth, minwidth*9-displacement, minwidth*2);
        // Draw the background
        canvas.drawColor(Color.WHITE);
        canvas.drawArc(mBigOval, 0.360.false, mPaint);
        canvas.drawArc(mBigOval1, 0.360.false, mPaint1);


        if (viewContinue){
            displacement += SWEEP_INC;
            if (displacement > minwidth*7) {
              viewContinue=false;
            }
            / / refresh the View
            invalidate();
        }
Copy the code

3. Change the constant speed

Increase the value of displacement as appropriate. The following

        if (viewContinue){
            displacement += SWEEP_INC;
            if (displacement>minwidth*2){
                displacement+=2;
            }
            if (displacement > minwidth*7) {
              viewContinue=false; } // refresh View invalidate(); }Copy the code

4. Repeat the animation

Effect:

Add another identifier, and again, make displacement smaller.

  if (viewContinue){
            displacement += SWEEP_INC;
            if (displacement>minwidth*2){
                displacement+=2;
            }
            if (displacement > minwidth*7) {
              viewContinue=false;
                viewContinue1=true; } // refresh View invalidate(); }if (viewContinue1){
           displacement -= SWEEP_INC;
           if (displacement<minwidth*5){
               displacement-=2;
           }
           if (displacement <0) {
               viewContinue1=false;
               viewContinue=true; } // refresh View invalidate(); }Copy the code

If only one round trip is required, the value of viewContinue is not set to true in viewContinue1.

5. The source code

public class MySampleView extends View {
    private int mWidth;
    private int mHeight;
    private int useWidth, minwidth;
    private Paint mPaint,mPaint1;
    private Paint mFramePaint;
    private RectF mBigOval,mBigOval1;
    private float displacement;
    private boolean viewContinue=true,viewContinue1=false;

    private static final float SWEEP_INC = 2;

    public MySampleView(Context context) {
        super(context);
    }

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

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MySampleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    private void init(a) {
        initPaint();
    }
    private void initPaint(a) {
        / / initialization
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(0x88FF0000);

        mPaint1 = new Paint();
        mPaint1.setAntiAlias(true);
        mPaint1.setStyle(Paint.Style.FILL);
        mPaint1.setColor(0x88888888);
        / / initialization
        mFramePaint = new Paint();
        mFramePaint.setAntiAlias(true);
        mFramePaint.setStyle(Paint.Style.STROKE);
        mFramePaint.setStrokeWidth(0);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        useWidth = mWidth;
        if(mWidth > mHeight) { useWidth = mHeight; }}@Override
    protected void onDraw(Canvas canvas) {
        init();
        // Define a minimum identifier
        minwidth = useWidth / 10;
        mBigOval = new RectF(minwidth+displacement, minwidth, minwidth*2+displacement, minwidth*2);
        mBigOval1 = new RectF(minwidth*8-displacement, minwidth, minwidth*9-displacement, minwidth*2);
        // Draw the background
        canvas.drawColor(Color.WHITE);
        //canvas.drawRect(mBigOval, mFramePaint);
        canvas.drawArc(mBigOval, 0.360.false, mPaint);
        canvas.drawArc(mBigOval1, 0.360.false, mPaint1);


        if (viewContinue){
            displacement += SWEEP_INC;
            if (displacement>minwidth*2){
                displacement+=2;
            }
            if (displacement > minwidth*7) {
              viewContinue=false;
                viewContinue1=true;
            }
            / / refresh the View
            invalidate();
        }
       if (viewContinue1){
           displacement -= SWEEP_INC;
           if (displacement<minwidth*5){
               displacement-=2;
           }
           if (displacement <0) {
               viewContinue1=false;
               viewContinue=true;
           }
           / / refresh the Viewinvalidate(); }}}Copy the code

Four,

Through the implementation of the second case, it should be able to expand our thinking and achieve better dynamic effects. Compared with the blogger’s previous articles with similar effects, it can be regarded as simplifying complexity. Think it should be able to help you. Welcome to leave a message.