When we’re done everything, it will like this:
You can always set the speed of the animation to see more clearly what happened in these animations in the app demo (in the first screen).
Do you find it interesting? So let’s analyze it. There are a lot of things inside that we need to consider ?
Take a look to analysis the animations which these affects got
1.When quickly touch to the button, the like emoticon will change from the grey border with transparent background to blue background and the text Like next to the emoticon is the same too. And the animation, in this case, is the like emoticon tilt right, then tilt to the left and finally back to the original position, the text zoom out, then zoom in and then zoom out again to back to original size.
2.If you long touch the button, it will process in another direction. The like emoticon in button will tilt to the left a little bit and the text be to zoom out. At the same time box of group, emoticons appear and six emoticons are pushed up. Notice that the emoticons will be pushed up with order and zoom in until they lined up neatly. And if user doesn’t drag to anywhere but just release then, the button will be back to original status.
3.However, if you drag your fingers, the emoticon you’re focusing will be zoom in to about 3/2 times the origin and others will zoom out a little bit (and the box will be zoom in too). In addition, the short description text at the top of focusing emoticon will appear and come up with the emoticon.
4.You should notice that the drag area is not unlimited, if you drag too far from the box, the emoticon will lose focus and the size will be back to origin when they are pushed up. And if you come back to the drag area, you’ll focus the emoticon again. Uncomment the line at 776 (color: Colors.amber.withOpacity(0.5)) to show the touch area for clearer to trace if you want.
5.After long touch, if you release your fingers without any emoticon be chosen, the box will be disappeared and emoticons will be lower in order (reverse with time they were pushed up). In case you not choose any emoticon, the like emoticon in button will tilt left and text is zoom in to back to original position/size.
6.But if you focus to particular emoticon and release, that emoticon will move to the button with the curve and zoom out until it disappears. At the same time, the color of border, text and the emoticon in button will change too.
7.Finally, the last thing we need to do is add the sound well-timed with every animation.
At here, you can think that everything is pretty simple,…….yeah you’re right, but our biggest issue is that how to combine every animation together and make it work most similar like the origin FB does. If you would like to get the answer, please continue with me now ?
Layout the UI
First, we need to wrap all content with GestureDetector widget to detect which area user is dragging. Is user drag too far from the top or bottom of the box emoticon, or user focusing to the particular emoticon, we can easy to detect and handle it.
This widget has many touch event, you can check out at https://docs.flutter.io/flutter/widgets/GestureDetector-class.html but we just focus on the following methods:
onHorizontalDragEnd: when user end dragging.
onHorizontalDragUpdate: when user moves their fingers.
And inside the root, first, we have an empty container to make a blank space at the top with height value is 100. Then at the body, we have the box (cover the emoticons) and the emoticons. Next, we make the button and six emoticons again (for the curved move when user choose, these emoticons is separate with the six emoticons inside the box for easier to deal with it).
We also wrap the button by GestureDetector widget:
and inside the button, we’ll use
onTapDown: when a user first touches to the button.
onTapUp: when a user releases the button.
onTap: when a user releases the button too, but after calling onTapUp.
The order of execution of these callbacks is onTapDown -> onTapUp -> onTap
At here, maybe you ask why we use three of them because the button has to handle with the quick touch and the long touch to process two type of animation. At onTapDown, we’ll make a Timer to measure when release button, the user just quick touch or long touch. If the duration from onTapDown to onTapUp is larger than the value (at here I set is 250ms), it is a long touch.
In this article, we just take a look at some of the main content. For details code of particular part please check my source code at the end of the article. I’ve already commented in the code to help you guys trace easier ?
Handling the general animations
To make an animation mostly like FB, we need to do with a lot of animations but don’t worry, we will handle it carefully.
The variable isLiked to detect is user quick touch or not.
The variable whichIconUserChoose to detect finally which emoticon user choose.
The currentIconFocus and previousIconFocus to help us handle animation when the emoticon be focused, at that time the previous emoticon will be animated by the zoom out (and the other keeps their state if not, every emoticon will zoom out every time user change focus and it seem not smooth).
Two dragging variable to detect whether user touch inside or outside the area, when touch outside we make losing focus to the emoticon.
Handling the animation of button
To tilt and zoom the emoticon, we need to wrap it by Transform.scale and Transform.rotate widget. Notice that we need to create a function to convert animation ascending value to bounce value (Flutter doesn’t have the output range like React Native ?). And if you check my code, you may wonder why I don’t group text and emoticon in one widget Transform.scale to zoom once, but if do this, the position of emoticon and text will move a little bit (because at here, the center is the point in the middle between emoticon and text), and it will not similar like origin FB does.
With the text, the content of text will change depending on which emoticon user choose, we just check the whichIconUserChoose variable to return the suitable string text for particular emoticon. Then we do the same with the emoticon inside the button.
With long touch, what we need to focus is how to detect when user long touchand when quick touch. So we’ll create a Timer to deal with it. If user long touch, we will show the box and emoticons, if not, we just cancel the timer and process with quick touch.
And about the change color of text, border… pretty simple, so we pass through it. Check my source code later if you need more details.
Handling the box and group emoticons
In this animation, we notice the emoticon will be pushed up in order, but the box just appears or disappear. When user touch outside the area we’ve already defined, the user will lose focus, and the emoticons and box will back to original size and position.
When user touches to inside area, we’ll the detect which touch position user locate and then animate the suitable emoticon for this position.
First, we check Y axis to detect if the user drag inside or outside the area.
Second, we check X axis to detect which emoticon will be focused.
You also notice that when user release button, in common, we just reverse the animation but in this case, you can see that when push up, the like emoticon will come first and when going down, the like emoticon be pushed down first again. But in this case, if you use reverse, the first emoticon be pushed down is the angry emoticon.
Why this happens, because when you forward, the start time of angry emoticon is the last, and when reverse, the last will become the first -> the angry emoticon (but what we need is the like emoticon). The solution is before reverse, we’ll set the value of the animation then reverse as normal.
Handling curved move emoticon when user choose it
Actually, we will render six emoticons, and checking is there any emoticon be chosen, we will show it and curved move by top left position and zoom out the size at the same time.
Flutter doesn’t let us render a null, so we just render an empty Container widget to replace the hide status.
Playing with images and sounds
We need some gif emoticons and short audios to make these animations more lively. The emoticon I found from some websites so maybe it’s a bit different because I can’t find the original emoticon from FB. With the sound, I recorded from external audio, then cut and amplify, so it may be not perfect. But overall I think it’s pretty similar with the origin.
Also, need to add the suitable packages to play these audios, the audioplayer package helps us to play, pause and stop any audio. The path_provider will give us a path of these audios file.
All audios are played at local, so we don’t need any permission.
And implement them, notice that we have to stop all the audio are playing first, then play the new because sometimes, the previous audio does not reach to the end yet but another will start because user changes their action too quickly.
The variable nameSound is just the name of an audio file, example: box_up.mp3
Summary
So, we just pass the main things to make an animation like Facebook Reactions.
I know that it’s not absolutely the same origin but after article, I’m sure that we’ll know more about Flutter animation and which things Facebook does with their reactions. Inside an interesting interactive effect is include a lot of single animation combine together and works smoothly miraculously.
If you guys have any questions. Please feedback so we can discuss and improve each other.
My source code is available at:
React Native version is here:
Thanks for taking the time to read ?
More where this came from
This story is published in Noteworthy, where thousands come every day to learn about the people & ideas shaping the products we love.
Follow our publication to see more stories featured by the Journal team.
Source: https://medium.com/@duytq94/facebook-reactions-with-flutter-9019ce8b95b8
Written by
Quang Duy Tran
My profile: https://duytq94.github.io/