I implemented this animation and share the full source code in here
First, let’s look at the big flow of implementing pass animations.
Draw a path to animate.
Start the path animation.
Draw a path to animate.
I have declared a member variable called mSrcPath which contains the information to draw on the canvas.
The onSizeChanged() method, which is called when the size changes, creates a path based on the view size.
The contents of the path are defined in the makeMenuArrowPath() method.
I then used the onDraw() method to draw the path.
The implementation part of the makeMenuArrowPath() method is shown below.
It’s just a part of creating a path, and It’s just modularization the path you want to animate.
Start the path animation.
Animation will start when you call the startPathAnimation() method.
I passed the beginning of the path and the end of the path to the parameters of the ObjectAnimator.ofFloat() method.
Note that the start and end values are shifted backward.
The reason for this is related to the behavior of the DashPathEffect class, which is the heart of Path animation.
More information can be found on the Romain Guy’s blog.
I overriding onDraw() method that called invalidate() on the setPhase() method, which is called whenever the value changes.
And I calls invalidate() method on the setPhase() method, which is called whenever the value changes.
As the result, the onDraw() method animates the path by drawing a new value.
The result of executing the above code is the same as the video below.
Now, let’s implement it as closely as possible to Apostol Voicu’s work we have seen above.
First, let’s change each corner of the path to look round.
Paint.setStrokeCap(Paint.Cap.ROUND) method call rounds the end of the path.
Paint.setStrokeJoin (Paint.Join.ROUND) method call rounds the parts of the path that are connected to each other.
Compared to the first image, you can see that the end of the path and the connected parts have changed smoothly.
Now, let’s look briefly at what I have implemented to implement the original work.
The original work will not be animated from the beginning to the complete form as seen in the above video.
As the segments move, the part at the end is finally drawn on the screen.
In order to implement this animation, I have removed the existing method and separated the Animator into two.
arrowAnimator and menuAnimator animators to specify where the current path should be drawn.
pathLengthAnimator animator to specify the length of the current path and specifies how far to draw it.
The setMenuPhase() method, which is called whenever the value changes in the menuAnimator, sets the current path to be drawn.
Within this method, I use the PathMeasure.getSegment() method to get the path for the start and end points and save it in mCurPath.
And in the original work, when drawing the menu path, the top part of the menu should be drawn as well, so I checked the status as below code and stored it in mCurPath too.
I then draw the mCurPath inside the onDraw() method by calling the invalidate() in setMenuPhase()method.
For reference, I gave an extra pass to the path to give it an overshooting effect like the original.
When changing to the menu and changing to Arrow, the paths overshooting each other are different.
For convenience of calculation and maintainability, I divided the path into two.
It is helpful to refer to MenuArrowAnimationButton.java.
The completed animation is as follows.
You can get the full source code of Menu/Arrow Animation by Apostol Voicu on my GitHub