The above article explained what a bezier curve is and how to draw it using the AndroidApi. So in this video we’re going to do some advanced Bezier curve animations.

1. Flowing waves

Demo renderings:

Implementation idea:Divide the screen width into 4 parts, half of which is a wavelength, one wavelength (0- “1/2) must have a peak, one trough. () one wavelength using Bezier curve) draw from the left side of the screen with 2/3 more wavelengths, set animation (moving bezier curve fixed point and control point to achieve translation wave effect) infinite cycle, start animation.

Code implementation: draw closed wave

@Override protected void onDraw(Canvas canvas) { Path path = new Path(); int itemWidth = weight / 2; path.moveTo(-3 * itemWidth, height / 2); for (int i = -3; i < 2; i++) { int controlX = i * itemWidth; path.quadTo(itemWidth / 2 + controlX + offset, getWaveHeight(i), controlX + itemWidth + offset, height / 2); } path.lineTo(weight, height); path.lineTo(0, height); path.close(); DrawPath (path, mWaveViewPaint); Private int getWaveHeight(int count) {if (count % 2 == 0) {return height / 2-170; private int getWaveHeight(int count) {return height / 2-170; } return height / 2 + 170; }Copy the code

Open animation

/** * private void start() {isStart = true; if(onStartListener! =null){ onStartListener.onIsStart(true); } animator = ValueAnimator.ofFloat(0, weight); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float animatorValue = (float) animation.getAnimatedValue(); offset = animatorValue; postInvalidate(); }}); animator.setDuration(1500); animator.setRepeatCount(ValueAnimator.INFINITE); // Repeat animator.start() an unlimited number of times; }Copy the code

Expose interfaces

public interface onStartListener { void onIsStart(boolean isStart); } public onStartListener onStartListener; public void setOnStart(onStartListener onStartListener) { this.onStartListener = onStartListener; } /** * public void stop() {isStart = false; if(onStartListener! =null){ onStartListener.onIsStart(false); } animator.cancel(); } public void isStart(){ if(isStart){ stop(); }else{ start(); }}Copy the code

2. Falling marbles

Demo renderings:

Implementation principle: draw the ball and rope (rope using Bezier curve drawing) preparation, the ball accelerated down, down to parallel with the rope, the rope with the ball down, down to the lowest point, the ball rebound rope then rebound deceleration upward, the ball out of the rope after the rope back to the initial position. Activity consists of AccelerateInterpolator () controlling accelerated motion, and decelerating motion. Modifying the control points of the Bezier curve to modify the position of the rope, nothing very simple.

Code: Draw

@Override protected void onDraw(Canvas canvas) { canvas.drawCircle(30, height / 2+500, 25, mLineCirclePaint); DrawCircle (width -30, height / 2+500, 25, mLineCirclePaint); drawCircle(width -30, height / 2+500, 25, mLineCirclePaint); DrawCircle (width / 2, height / 2+500 + mballControlly, 60, mballPaint); // Draw the falling ball /* Bezier curve drawing rope */ mPath. Reset (); mPath.moveTo(23, height / 2+500); mPath.quadTo(mLineControllx, height / 2+500 + mLineControlly, width - 23, height / 2+500); canvas.drawPath(mPath, mLinePaint); }Copy the code

animation

Public void startAni() {downAnimator = valueanimator.offloat (mballMaxy, mballMiny); downAnimator = downanimator.offloat (mballMaxy, mballMiny); Downanimator.setduration (1500); downAnimator.setInterpolator(new AccelerateInterpolator()); downAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mballControlly = (float) animation.getAnimatedValue(); if (height / 2 + mballControlly >= height / 2) { mLineControlly = (float) ((float) (animation.getAnimatedValue()) * 2.5); } postInvalidate(); }}); downAnimator.start(); downAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { startUpAnimator(); }}); UpAnimator = valueAnimator.offloat (mballMiny, mballMaxy); upAnimator = valueanimator.offloat (mballMiny, mballMaxy); . / / 300 - > - 900 upAnimator setDuration ((long) (1500 * 0.7)); upAnimator.setInterpolator(new DecelerateInterpolator()); upAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float animatedValue = (float) animation.getAnimatedValue(); mballControlly = animatedValue; If (mballControlly+height/2>=height/2+mballMaxy*0.4&&mballControlly<150){mballecontrolly =animatedValue; }/*else if(mballControlly+height/2<height/2+mballMaxy/3) { mLineControlly = -animatedValue / 2; }*/ if(animatedValue<=-898){// If (animatedValue<=-898){// If (animatedValue<=-898){ } postInvalidate(); }}); upAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { startDownAnimator(); }}); } public void startUpAnimator() {if (upAnimator! = null && upAnimator.getValues() ! = null && upAnimator.getValues().length > 0 && ! upAnimator.isRunning()) { upAnimator.start(); Public void startDownAnimator() {if (downAnimator! = null && downAnimator.getValues() ! = null && downAnimator.getValues().length > 0 && ! downAnimator.isRunning()) { downAnimator.start(); }}Copy the code

And that’s the end of it

Attach the project source code

Program source code