Animate a complex radial menu 🥞 in Flutter at can translate, scale, and rotate at 60 FPS from scratch https://fireship.io/lessons/flutter-radial-menu-staggered-animations/

- Flutter Animation https://flutter.dev/docs/development/ui/animations
- Flutter Performance https://flutter.dev/docs/testing/ui-performance

#flutter #animation #butter
2024-02-04T06:56:09.516Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
18d047fa-51a8-4345-a483-7d9e30e5daf1
508920e4aa1b4e6cd46ffea7402c2927ef1a79b07dd433dc31d71f9ff6b78234
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
Building a butter smooth UI is extremely important in the world of native apps.
It only takes a small amount of jank for people to think your app sucks.
That's why one of my favorite things about Flutter is how beautifully it renders the animations.
We can use the built in profiler to see that we easily achieve 60 frames per second even for this complex rotating radio menu.
In today's video, you'll learn all about Flutter animations by building this menu Scratch.
If you're new here like and subscribe and you can find the full source code on Fireship IO.
Before we get started I have a confession to make.
In college I failed trigonometry.
I vividly remember Scoring 0 out of 100 points on the midterm and I probably didn't even take the final.
And that's not good because we need to use trigonometry in this video to determine where to place the different elements on the menu.
We take a closer look at this menu, we actually have 10 different buttons stacked on top of each other.
The open and close buttons stay in the middle and then they scale up and down depending on whether or not the menu is opened or closed.
When opened, all of the outer buttons will be translated or moved to a specific bearing from the center point.
This is where trig comes into play because we need to calculate a specific x y coordinate based on an angle from the center.
But don't worry too much about that.
It's actually a very easy calculation.
And this entire demo only takes about a 150 lines of code, which is pretty crazy.
And as a final touch, we'll also add a rotation to the entire stack of buttons.
So that way, it rotates clockwise when opening and counterclockwise when closing.
To get started, you'll need to have a Flutter app, and then I also have vector math installed and optionally Font Awesome for some better icons in the material.
And if we go into our main dart file, you can see that I'm importing dart math, and then I'm importing radians from vector math.
And it's important to do the import like this because it has some conflicting classes with Flutter.
Now we'll go down here to our material app, and we'll just add a scaffold.
And for this demo, we'll just have the menu fill up the entire screen.
And for that, we can use a sized box and have it expand to fill out the entire viewport.
And then the child for that box will be our custom radial menu widget.
When working with animations, the first thing you'll usually start with is a Stateful widget.
The only thing this widget is concerned with is defining the animation controller, which itself controls the duration of the animation as well as the controls is to tell it to play in forward or in reverse.
What it doesn't control is the actual animation properties or the UI elements that are being animated.
First thing we'll do is add a mix into this class called the single ticker provider state mix in.
This will put the widget in ticker mode, which makes animations possible.
The next thing we'll do is declare our animation controller and then we'll actually define it inside of the init lifecycle hook.
The most important aspect of the animation controller is the duration.
At the end of the video, we'll stagger animations, which will all be relative to the duration that we define here.
So in this case, the total duration of the animation is 900 milliseconds.
We also have to pass the this context to v sync, which is just a piece of boilerplate for animation controllers.
In order to achieve 60 frames per 2nd, this animation controller will tick every 16 milliseconds.
I have it commented out here, but you could add a listener to this controller and then set the state every time it ticks.
But we'll be using an animated builder in the next step, which makes this part unnecessary.
Now we'll define the build method for this widget, and you'll see it returns a radial animation widget, which we'll define next.
Just notice how it takes the animation controller as a property to its constructor.
We'll be using the same controller to orchestrate multiple different animations at the same time.
All of the animation logic will be handled by this radial animation widget.
In order for it to take the animation controller as an input property, we add it to the constructor here and then call super.
From there, we'll define the build method, and it will start with an animated builder.
An animated builder takes 2 main arguments.
The first one is just the animation controller, And the second one is a function to build the UI.
So, basically, every time the animation controller ticks, it will run this builder function to rebuild all your widgets.
We can control the state of this animation both in the stateless widget or in the stateful widget above.
Because this is a menu, I wanna make these methods a little more clear, so I'm defining my own custom methods called open and close.
Open will run the animation in forward and then close will run the animation in reverse.
Now we can go up to our builder function, and the first thing I'm going to define is a stack because, remember, all the buttons are just stacked on top of each other.
In the children array, I'll go ahead and add 2 floating action buttons.
And because we're working with a stack, only the last button should be visible.
That means you want the button that will open the menu initially to be the last item in the stack.
If we open this on a device, we should see our blue open menu button.
And if we take that out of the stack, then we'll see the close button.
That takes care of the initial setup.
Now let's build the first animation that toggles this open and close button.
For that, we're going to zoom out a bit and go to the top of our radial animation button and first define a property called scale that is typed to an animation of a number.
Then we'll define scale as a tween.
A tween is one of those words that always makes me nervous when I see it.
However, they're actually very simple, and they just translate to in between.
So you give it a starting value and an ending value, and it will calculate everything in between.
In this case, we're animating the scale of an element.
By giving it a starting point of 1.5, it will be 150% of its normal size.
And then at the end of the animation, it will be 0% or invisible.
The next thing we need to do is bind this tween to our actual animation controller.
That gives it an actual duration to know how to calculate the in between values.
You could just pass in the animation controller directly here, but more often than not, you'll use a curved animation to make your animations a little more exciting.
I'm using fast out slow in, but there's a lot of different curves you can experiment with here.
The last piece of this puzzle is determining where to apply this animation in the widget tree.
The scale animation is only going to apply to our open and close buttons in the middle.
Flutter has this super useful thing called a transform widget, And it has a few static methods to rotate, scale, and translate a child widget, but it can also be used for super complex perspective based 3 d animations.
So notice here how we wrapped our floating action button in the transform scale.
And then for the scale argument, we're passing at the scale value from the tween animation.
So that means every animation tick or every 16 milliseconds, it will update the scale value of this element when it's animating.
Now, we'll go ahead and wrap the other button in Transform Scale as well.
But you'll notice right now they're both using the same animation, so they'll be doing the same thing at the same time.
We could write an entirely different animation for each button, but we can also be kind of clever here and instead just subtract 1 from the scale value, which will give us the opposite animation for the closing button.
Always see if you can be clever first before writing a bunch of extra code.
That completes the first animation.
If we open it up on a device, we should see the button scaling in and out when clicked.
The next challenge is to create a whole bunch of buttons that pop out of the middle when the menu is activated.
We'll go back up to the constructor and add another animation that's very similar to our scale animation.
This time, we'll go ahead and call it translation.
We'll give it a starting value of 0 and an ending value of 100.
Then we'll define a curved animation.
Then, again, make sure to experiment with the different curves.
You have a whole bunch of different options here.
Now we definitely don't want to hard code a bunch of floating action buttons 1 by 1.
Instead, I'm writing a method called build button which will take an angle as an argument which is in degrees and then it will also take an optional color and icon.
This This is the part where a little bit of trigonometry is going to help us write very concise code.
What we wanna do is translate each individual button at a specific angle from the center point of this menu.
This needs to be done in radians and not degrees, but degrees are a lot easier to work with if you're a human being because it's easy to reason about a circle when you think of it in 360 degrees.
The first thing we'll do is convert that angle argument to radians.
Then we'll define a transform widget.
And that allows us to actually pass in a transformation matrix.
This is really cool because you can chain together different transformations by using Dart's double dot notation.
We're not going to do this today, but in theory, we could also chain together a scale and a rotation if we wanted 2.
In this demo, we're only concerned about the translation, but we need to calculate the translation based on the x y value from the center point of the circle.
We do that by taking the current translation value and then multiplying it by the cosine of the radians.
That will give us the x value.
And then to get the y value, we just take the sine of the radians.
And even as a failed trigonometry student, I think I understand this.
And that's all it takes to calculate that translation.
The only other thing we have to do here is add a child widget which will just be a floating action button that will take our icon and background color arguments.
Now we can come back up to the widget tree to our stack And just call this button for every item that we want to add to the menu.
We'll put the first button at 0 degrees, the next one at 45, the next one at 90, and so on.
If you open up the app, you should have an effect that looks like this.
At this point, the buttons are going in and out, but there's no rotation going on yet.
What I wanna show you is how to rotate the entire Widget stack But, do it in a way that's offset from the main animation timeline.
This is what you would call a staggered animation.
First, we'll set up another number tween And then we'll start at 0 and rotate around the entire circle to 360 degrees.
We can make this staggered by going into the curved animation and then instead of providing a curve We'll provide an interval.
This will tell the animation to start executing at a certain point in the animation timeline.
With the first value being 0, that means the animation will start right away.
But the second value is 0.7 which means it will end at 70% into the animation itself.
In other words, the rotation animation will happen faster than the rest of the animation timeline.
And now the interval itself will take the actual curve argument.
So that takes care of the animation.
Now let's come down to the widget tree then we'll wrap the entire stack in the transform rotate method.
Now the stack will become the child of this widget and then we'll set the angle value to the rotation value.
The angle is also based on radians, so you'll wanna do that conversion there if you're looking to do one full circle with 360 degrees.
Now open up the demo on a device, and you should have the super smooth 60 frames per second animation.
And if you don't believe me, Flutter has a built in profiler.
So just run Flutter run flag profile and you should see that you have Plenty of room to spare for even more animation and UI painting.
I'm gonna go ahead and wrap things up there.
If you have any UI elements from popular mobile apps that you might want to see clone in this channel, let me know in the comments.
And if this video helped you, please like and subscribe.
Thanks for watching and I will talk to you soon.

Speaker 0: Building a butter smooth UI is extremely important in the world of native apps. It only takes a small amount of jank for people to think your app sucks. That's why one of my favorite things about Flutter is how beautifully it renders the animations. We can use the built in profiler to see that we easily achieve 60 frames per second even for this complex rotating radio menu. In today's video, you'll learn all about Flutter animations by building this menu Scratch.

If you're new here like and subscribe and you can find the full source code on Fireship IO. Before we get started I have a confession to make. In college I failed trigonometry. I vividly remember Scoring 0 out of 100 points on the midterm and I probably didn't even take the final. And that's not good because we need to use trigonometry in this video to determine where to place the different elements on the menu.

We take a closer look at this menu, we actually have 10 different buttons stacked on top of each other. The open and close buttons stay in the middle and then they scale up and down depending on whether or not the menu is opened or closed. When opened, all of the outer buttons will be translated or moved to a specific bearing from the center point. This is where trig comes into play because we need to calculate a specific x y coordinate based on an angle from the center. But don't worry too much about that.

It's actually a very easy calculation. And this entire demo only takes about a 150 lines of code, which is pretty crazy. And as a final touch, we'll also add a rotation to the entire stack of buttons. So that way, it rotates clockwise when opening and counterclockwise when closing. To get started, you'll need to have a Flutter app, and then I also have vector math installed and optionally Font Awesome for some better icons in the material.

And if we go into our main dart file, you can see that I'm importing dart math, and then I'm importing radians from vector math. And it's important to do the import like this because it has some conflicting classes with Flutter. Now we'll go down here to our material app, and we'll just add a scaffold. And for this demo, we'll just have the menu fill up the entire screen. And for that, we can use a sized box and have it expand to fill out the entire viewport.

And then the child for that box will be our custom radial menu widget. When working with animations, the first thing you'll usually start with is a Stateful widget. The only thing this widget is concerned with is defining the animation controller, which itself controls the duration of the animation as well as the controls is to tell it to play in forward or in reverse. What it doesn't control is the actual animation properties or the UI elements that are being animated. First thing we'll do is add a mix into this class called the single ticker provider state mix in.

This will put the widget in ticker mode, which makes animations possible. The next thing we'll do is declare our animation controller and then we'll actually define it inside of the init lifecycle hook. The most important aspect of the animation controller is the duration. At the end of the video, we'll stagger animations, which will all be relative to the duration that we define here. So in this case, the total duration of the animation is 900 milliseconds.

We also have to pass the this context to v sync, which is just a piece of boilerplate for animation controllers. In order to achieve 60 frames per 2nd, this animation controller will tick every 16 milliseconds. I have it commented out here, but you could add a listener to this controller and then set the state every time it ticks. But we'll be using an animated builder in the next step, which makes this part unnecessary. Now we'll define the build method for this widget, and you'll see it returns a radial animation widget, which we'll define next.

Just notice how it takes the animation controller as a property to its constructor. We'll be using the same controller to orchestrate multiple different animations at the same time. All of the animation logic will be handled by this radial animation widget. In order for it to take the animation controller as an input property, we add it to the constructor here and then call super. From there, we'll define the build method, and it will start with an animated builder.

An animated builder takes 2 main arguments. The first one is just the animation controller, And the second one is a function to build the UI. So, basically, every time the animation controller ticks, it will run this builder function to rebuild all your widgets. We can control the state of this animation both in the stateless widget or in the stateful widget above. Because this is a menu, I wanna make these methods a little more clear, so I'm defining my own custom methods called open and close.

Open will run the animation in forward and then close will run the animation in reverse. Now we can go up to our builder function, and the first thing I'm going to define is a stack because, remember, all the buttons are just stacked on top of each other. In the children array, I'll go ahead and add 2 floating action buttons. And because we're working with a stack, only the last button should be visible. That means you want the button that will open the menu initially to be the last item in the stack.

If we open this on a device, we should see our blue open menu button. And if we take that out of the stack, then we'll see the close button. That takes care of the initial setup. Now let's build the first animation that toggles this open and close button. For that, we're going to zoom out a bit and go to the top of our radial animation button and first define a property called scale that is typed to an animation of a number.

Then we'll define scale as a tween. A tween is one of those words that always makes me nervous when I see it. However, they're actually very simple, and they just translate to in between. So you give it a starting value and an ending value, and it will calculate everything in between. In this case, we're animating the scale of an element.

By giving it a starting point of 1.5, it will be 150% of its normal size. And then at the end of the animation, it will be 0% or invisible. The next thing we need to do is bind this tween to our actual animation controller. That gives it an actual duration to know how to calculate the in between values. You could just pass in the animation controller directly here, but more often than not, you'll use a curved animation to make your animations a little more exciting.

I'm using fast out slow in, but there's a lot of different curves you can experiment with here. The last piece of this puzzle is determining where to apply this animation in the widget tree. The scale animation is only going to apply to our open and close buttons in the middle. Flutter has this super useful thing called a transform widget, And it has a few static methods to rotate, scale, and translate a child widget, but it can also be used for super complex perspective based 3 d animations. So notice here how we wrapped our floating action button in the transform scale.

And then for the scale argument, we're passing at the scale value from the tween animation. So that means every animation tick or every 16 milliseconds, it will update the scale value of this element when it's animating. Now, we'll go ahead and wrap the other button in Transform Scale as well. But you'll notice right now they're both using the same animation, so they'll be doing the same thing at the same time. We could write an entirely different animation for each button, but we can also be kind of clever here and instead just subtract 1 from the scale value, which will give us the opposite animation for the closing button.

Always see if you can be clever first before writing a bunch of extra code. That completes the first animation. If we open it up on a device, we should see the button scaling in and out when clicked. The next challenge is to create a whole bunch of buttons that pop out of the middle when the menu is activated. We'll go back up to the constructor and add another animation that's very similar to our scale animation.

This time, we'll go ahead and call it translation. We'll give it a starting value of 0 and an ending value of 100. Then we'll define a curved animation. Then, again, make sure to experiment with the different curves. You have a whole bunch of different options here.

Now we definitely don't want to hard code a bunch of floating action buttons 1 by 1. Instead, I'm writing a method called build button which will take an angle as an argument which is in degrees and then it will also take an optional color and icon. This This is the part where a little bit of trigonometry is going to help us write very concise code. What we wanna do is translate each individual button at a specific angle from the center point of this menu. This needs to be done in radians and not degrees, but degrees are a lot easier to work with if you're a human being because it's easy to reason about a circle when you think of it in 360 degrees.

The first thing we'll do is convert that angle argument to radians. Then we'll define a transform widget. And that allows us to actually pass in a transformation matrix. This is really cool because you can chain together different transformations by using Dart's double dot notation. We're not going to do this today, but in theory, we could also chain together a scale and a rotation if we wanted 2.

In this demo, we're only concerned about the translation, but we need to calculate the translation based on the x y value from the center point of the circle. We do that by taking the current translation value and then multiplying it by the cosine of the radians. That will give us the x value. And then to get the y value, we just take the sine of the radians. And even as a failed trigonometry student, I think I understand this.

And that's all it takes to calculate that translation. The only other thing we have to do here is add a child widget which will just be a floating action button that will take our icon and background color arguments. Now we can come back up to the widget tree to our stack And just call this button for every item that we want to add to the menu. We'll put the first button at 0 degrees, the next one at 45, the next one at 90, and so on. If you open up the app, you should have an effect that looks like this.

At this point, the buttons are going in and out, but there's no rotation going on yet. What I wanna show you is how to rotate the entire Widget stack But, do it in a way that's offset from the main animation timeline. This is what you would call a staggered animation. First, we'll set up another number tween And then we'll start at 0 and rotate around the entire circle to 360 degrees. We can make this staggered by going into the curved animation and then instead of providing a curve We'll provide an interval.

This will tell the animation to start executing at a certain point in the animation timeline. With the first value being 0, that means the animation will start right away. But the second value is 0.7 which means it will end at 70% into the animation itself. In other words, the rotation animation will happen faster than the rest of the animation timeline. And now the interval itself will take the actual curve argument.

So that takes care of the animation. Now let's come down to the widget tree then we'll wrap the entire stack in the transform rotate method. Now the stack will become the child of this widget and then we'll set the angle value to the rotation value. The angle is also based on radians, so you'll wanna do that conversion there if you're looking to do one full circle with 360 degrees. Now open up the demo on a device, and you should have the super smooth 60 frames per second animation.

And if you don't believe me, Flutter has a built in profiler. So just run Flutter run flag profile and you should see that you have Plenty of room to spare for even more animation and UI painting. I'm gonna go ahead and wrap things up there. If you have any UI elements from popular mobile apps that you might want to see clone in this channel, let me know in the comments. And if this video helped you, please like and subscribe.

Thanks for watching and I will talk to you soon.
Building a butter smooth UI is extremely important in the world of native apps. It only takes a small amount of jank for people to think your app sucks.
That's why one of my favorite things about Flutter is how beautifully it renders the animations. We can use the built in profiler to see that we easily achieve 60 frames per second even for this complex rotating radio menu. In today's video, you'll learn all about Flutter animations by building this menu Scratch. If you're new here like and subscribe and you can find the full source code on Fireship IO. Before we get started I have a confession to make. In college I failed trigonometry. I vividly remember Scoring 0 out of 100 points on the midterm and I probably didn't even take the final.
animation
video gaming
And that's not good because we need to use trigonometry in this video to determine where to place the different elements on the menu. We take a closer look at this menu, we actually have 10 different buttons stacked on top of each other. The open and close buttons stay in the middle and then they scale up and down depending on whether or not the menu is opened or closed. When opened, all of the outer buttons will be translated or moved to a specific bearing from the center point. This is where trig comes into play because we need to calculate a specific x y coordinate based on an angle from the center. But don't worry too much about that. It's actually a very easy calculation. And this entire demo only takes about a 150 lines of code, which is pretty crazy.
And as a final touch, we'll also add a rotation to the entire stack of buttons. So that way, it rotates clockwise when opening and counterclockwise when closing. To get started, you'll need to have a Flutter app, and then I also have vector math installed and optionally Font Awesome for some better icons in the material.
animation
And if we go into our main dart file, you can see that I'm importing dart math, and then I'm importing radians from vector math. And it's important to do the import like this because it has some conflicting classes with Flutter. Now we'll go down here to our material app, and we'll just add a scaffold.
And for this demo, we'll just have the menu fill up the entire screen. And for that, we can use a sized box and have it expand to fill out the entire viewport. And then the child for that box will be our custom radial menu widget. When working with animations, the first thing you'll usually start with is a Stateful widget. The only thing this widget is concerned with is defining the animation controller, which itself controls the duration of the animation as well as the controls is to tell it to play in forward or in reverse. What it doesn't control is the actual animation properties or the UI elements that are being animated. First thing we'll do is add a mix into this class called the single ticker provider state mix in. This will put the widget in ticker mode, which makes animations possible. The next thing we'll do is declare our animation controller and then we'll actually define it inside of the init lifecycle hook. The most important aspect of the animation controller is the duration. At the end of the video, we'll stagger animations, which will all be relative to the duration that we define here. So in this case, the total duration of the animation is 900 milliseconds. We also have to pass the this context to v sync, which is just a piece of boilerplate for animation controllers. In order to achieve 60 frames per 2nd, this animation controller will tick every 16 milliseconds. I have it commented out here, but you could add a listener to this controller and then set the state every time it ticks. But we'll be using an animated builder in the next step, which makes this part unnecessary. Now we'll define the build method for this widget, and you'll see it returns a radial animation widget, which we'll define next. Just notice how it takes the animation controller as a property to its constructor. We'll be using the same controller to orchestrate multiple different animations at the same time. All of the animation logic will be handled by this radial animation widget. In order for it to take the animation controller as an input property, we add it to the constructor here and then call super. From there, we'll define the build method, and it will start with an animated builder. An animated builder takes 2 main arguments. The first one is just the animation controller, And the second one is a function to build the UI. So, basically, every time the animation controller ticks, it will run this builder function to rebuild all your widgets. We can control the state of this animation both in the stateless widget or in the stateful widget above. Because this is a menu, I wanna make these methods a little more clear, so I'm defining my own custom methods called open and close. Open will run the animation in forward and then close will run the animation in reverse. Now we can go up to our builder function, and the first thing I'm going to define is a stack because, remember, all the buttons are just stacked on top of each other. In the children array, I'll go ahead and add 2 floating action buttons.
animation
graphic design
visualization
programming
architecture
toys
video gaming
And because we're working with a stack, only the last button should be visible. That means you want the button that will open the menu initially to be the last item in the stack. If we open this on a device, we should see our blue open menu button.
And if we take that out of the stack, then we'll see the close button. That takes care of the initial setup. Now let's build the first animation that toggles this open and close button. For that, we're going to zoom out a bit and go to the top of our radial animation button and first define a property called scale that is typed to an animation of a number. Then we'll define scale as a tween. A tween is one of those words that always makes me nervous when I see it. However, they're actually very simple, and they just translate to in between. So you give it a starting value and an ending value, and it will calculate everything in between. In this case, we're animating the scale of an element. By giving it a starting point of 1.5, it will be 150% of its normal size. And then at the end of the animation, it will be 0% or invisible. The next thing we need to do is bind this tween to our actual animation controller. That gives it an actual duration to know how to calculate the in between values. You could just pass in the animation controller directly here, but more often than not, you'll use a curved animation to make your animations a little more exciting. I'm using fast out slow in, but there's a lot of different curves you can experiment with here. The last piece of this puzzle is determining where to apply this animation in the widget tree. The scale animation is only going to apply to our open and close buttons in the middle. Flutter has this super useful thing called a transform widget, And it has a few static methods to rotate, scale, and translate a child widget, but it can also be used for super complex perspective based 3 d animations. So notice here how we wrapped our floating action button in the transform scale. And then for the scale argument, we're passing at the scale value from the tween animation. So that means every animation tick or every 16 milliseconds, it will update the scale value of this element when it's animating. Now, we'll go ahead and wrap the other button in Transform Scale as well. But you'll notice right now they're both using the same animation, so they'll be doing the same thing at the same time. We could write an entirely different animation for each button, but we can also be kind of clever here and instead just subtract 1 from the scale value, which will give us the opposite animation for the closing button. Always see if you can be clever first before writing a bunch of extra code. That completes the first animation. If we open it up on a device, we should see the button scaling in and out when clicked. The next challenge is to create a whole bunch of buttons that pop out of the middle when the menu is activated. We'll go back up to the constructor and add another animation that's very similar to our scale animation. This time, we'll go ahead and call it translation. We'll give it a starting value of 0 and an ending value of 100. Then we'll define a curved animation. Then, again, make sure to experiment with the different curves. You have a whole bunch of different options here. Now we definitely don't want to hard code a bunch of floating action buttons 1 by 1. Instead, I'm writing a method called build button which will take an angle as an argument which is in degrees and then it will also take an optional color and icon.
twitter
animation
measurement
modeling
robotics
graphic design
mathematics
geometry
This This is the part where a little bit of trigonometry is going to help us write very concise code. What we wanna do is translate each individual button at a specific angle from the center point of this menu. This needs to be done in radians and not degrees, but degrees are a lot easier to work with if you're a human being because it's easy to reason about a circle when you think of it in 360 degrees. The first thing we'll do is convert that angle argument to radians. Then we'll define a transform widget. And that allows us to actually pass in a transformation matrix. This is really cool because you can chain together different transformations by using Dart's double dot notation. We're not going to do this today, but in theory, we could also chain together a scale and a rotation if we wanted 2. In this demo, we're only concerned about the translation, but we need to calculate the translation based on the x y value from the center point of the circle.
geometry
mathematics
We do that by taking the current translation value and then multiplying it by the cosine of the radians. That will give us the x value. And then to get the y value, we just take the sine of the radians. And even as a failed trigonometry student, I think I understand this. And that's all it takes to calculate that translation. The only other thing we have to do here is add a child widget which will just be a floating action button that will take our icon and background color arguments.
mathematics
geometry
Now we can come back up to the widget tree to our stack And just call this button for every item that we want to add to the menu. We'll put the first button at 0 degrees, the next one at 45, the next one at 90, and so on. If you open up the app, you should have an effect that looks like this.
At this point, the buttons are going in and out, but there's no rotation going on yet. What I wanna show you is how to rotate the entire Widget stack But, do it in a way that's offset from the main animation timeline. This is what you would call a staggered animation. First, we'll set up another number tween And then we'll start at 0 and rotate around the entire circle to 360 degrees. We can make this staggered by going into the curved animation and then instead of providing a curve We'll provide an interval. This will tell the animation to start executing at a certain point in the animation timeline. With the first value being 0, that means the animation will start right away. But the second value is 0.7 which means it will end at 70% into the animation itself. In other words, the rotation animation will happen faster than the rest of the animation timeline. And now the interval itself will take the actual curve argument. So that takes care of the animation. Now let's come down to the widget tree then we'll wrap the entire stack in the transform rotate method. Now the stack will become the child of this widget and then we'll set the angle value to the rotation value. The angle is also based on radians, so you'll wanna do that conversion there if you're looking to do one full circle with 360 degrees. Now open up the demo on a device, and you should have the super smooth 60 frames per second animation. And if you don't believe me, Flutter has a built in profiler. So just run Flutter run flag profile and you should see that you have Plenty of room to spare for even more animation and UI painting. I'm gonna go ahead and wrap things up there. If you have any UI elements from popular mobile apps that you might want to see clone in this channel, let me know in the comments. And if this video helped you, please like and subscribe. Thanks for watching and I will talk to you soon.
animation
youtube
geometry
phones
documentary
robotics
streaming
Building a butter smooth UI is extremely important in the world of native apps. It only takes a small amount of jank for people to think your app sucks. That's why one of my favorite things about Flutter is how beautifully it renders the animations. We can use the built in profiler to see that we easily achieve 60 frames per second even for this complex rotating radio menu. In today's video, you'll learn all about Flutter animations by building this menu Scratch. If you're new here like and subscribe and you can find the full source code on Fireship IO. Before we get started I have a confession to make. In college I failed trigonometry. I vividly remember Scoring 0 out of 100 points on the midterm and I probably didn't even take the final. And that's not good because we need to use trigonometry in this video to determine where to place the different elements on the menu. We take a closer look at this menu, we actually have 10 different buttons stacked on top of each other. The open and close buttons stay in the middle and then they scale up and down depending on whether or not the menu is opened or closed. When opened, all of the outer buttons will be translated or moved to a specific bearing from the center point. This is where trig comes into play because we need to calculate a specific x y coordinate based on an angle from the center. But don't worry too much about that. It's actually a very easy calculation. And this entire demo only takes about a 150 lines of code, which is pretty crazy. And as a final touch, we'll also add a rotation to the entire stack of buttons. So that way, it rotates clockwise when opening and counterclockwise when closing. To get started, you'll need to have a Flutter app, and then I also have vector math installed and optionally Font Awesome for some better icons in the material. And if we go into our main dart file, you can see that I'm importing dart math, and then I'm importing radians from vector math. And it's important to do the import like this because it has some conflicting classes with Flutter. Now we'll go down here to our material app, and we'll just add a scaffold. And for this demo, we'll just have the menu fill up the entire screen. And for that, we can use a sized box and have it expand to fill out the entire viewport. And then the child for that box will be our custom radial menu widget. When working with animations, the first thing you'll usually start with is a Stateful widget. The only thing this widget is concerned with is defining the animation controller, which itself controls the duration of the animation as well as the controls is to tell it to play in forward or in reverse. What it doesn't control is the actual animation properties or the UI elements that are being animated. First thing we'll do is add a mix into this class called the single ticker provider state mix in. This will put the widget in ticker mode, which makes animations possible. The next thing we'll do is declare our animation controller and then we'll actually define it inside of the init lifecycle hook. The most important aspect of the animation controller is the duration. At the end of the video, we'll stagger animations, which will all be relative to the duration that we define here. So in this case, the total duration of the animation is 900 milliseconds. We also have to pass the this context to v sync, which is just a piece of boilerplate for animation controllers. In order to achieve 60 frames per 2nd, this animation controller will tick every 16 milliseconds. I have it commented out here, but you could add a listener to this controller and then set the state every time it ticks. But we'll be using an animated builder in the next step, which makes this part unnecessary. Now we'll define the build method for this widget, and you'll see it returns a radial animation widget, which we'll define next. Just notice how it takes the animation controller as a property to its constructor. We'll be using the same controller to orchestrate multiple different animations at the same time. All of the animation logic will be handled by this radial animation widget. In order for it to take the animation controller as an input property, we add it to the constructor here and then call super. From there, we'll define the build method, and it will start with an animated builder. An animated builder takes 2 main arguments. The first one is just the animation controller, And the second one is a function to build the UI. So, basically, every time the animation controller ticks, it will run this builder function to rebuild all your widgets. We can control the state of this animation both in the stateless widget or in the stateful widget above. Because this is a menu, I wanna make these methods a little more clear, so I'm defining my own custom methods called open and close. Open will run the animation in forward and then close will run the animation in reverse. Now we can go up to our builder function, and the first thing I'm going to define is a stack because, remember, all the buttons are just stacked on top of each other. In the children array, I'll go ahead and add 2 floating action buttons. And because we're working with a stack, only the last button should be visible. That means you want the button that will open the menu initially to be the last item in the stack. If we open this on a device, we should see our blue open menu button. And if we take that out of the stack, then we'll see the close button. That takes care of the initial setup. Now let's build the first animation that toggles this open and close button. For that, we're going to zoom out a bit and go to the top of our radial animation button and first define a property called scale that is typed to an animation of a number. Then we'll define scale as a tween. A tween is one of those words that always makes me nervous when I see it. However, they're actually very simple, and they just translate to in between. So you give it a starting value and an ending value, and it will calculate everything in between. In this case, we're animating the scale of an element. By giving it a starting point of 1.5, it will be 150% of its normal size. And then at the end of the animation, it will be 0% or invisible. The next thing we need to do is bind this tween to our actual animation controller. That gives it an actual duration to know how to calculate the in between values. You could just pass in the animation controller directly here, but more often than not, you'll use a curved animation to make your animations a little more exciting. I'm using fast out slow in, but there's a lot of different curves you can experiment with here. The last piece of this puzzle is determining where to apply this animation in the widget tree. The scale animation is only going to apply to our open and close buttons in the middle. Flutter has this super useful thing called a transform widget, And it has a few static methods to rotate, scale, and translate a child widget, but it can also be used for super complex perspective based 3 d animations. So notice here how we wrapped our floating action button in the transform scale. And then for the scale argument, we're passing at the scale value from the tween animation. So that means every animation tick or every 16 milliseconds, it will update the scale value of this element when it's animating. Now, we'll go ahead and wrap the other button in Transform Scale as well. But you'll notice right now they're both using the same animation, so they'll be doing the same thing at the same time. We could write an entirely different animation for each button, but we can also be kind of clever here and instead just subtract 1 from the scale value, which will give us the opposite animation for the closing button. Always see if you can be clever first before writing a bunch of extra code. That completes the first animation. If we open it up on a device, we should see the button scaling in and out when clicked. The next challenge is to create a whole bunch of buttons that pop out of the middle when the menu is activated. We'll go back up to the constructor and add another animation that's very similar to our scale animation. This time, we'll go ahead and call it translation. We'll give it a starting value of 0 and an ending value of 100. Then we'll define a curved animation. Then, again, make sure to experiment with the different curves. You have a whole bunch of different options here. Now we definitely don't want to hard code a bunch of floating action buttons 1 by 1. Instead, I'm writing a method called build button which will take an angle as an argument which is in degrees and then it will also take an optional color and icon. This This is the part where a little bit of trigonometry is going to help us write very concise code. What we wanna do is translate each individual button at a specific angle from the center point of this menu. This needs to be done in radians and not degrees, but degrees are a lot easier to work with if you're a human being because it's easy to reason about a circle when you think of it in 360 degrees. The first thing we'll do is convert that angle argument to radians. Then we'll define a transform widget. And that allows us to actually pass in a transformation matrix. This is really cool because you can chain together different transformations by using Dart's double dot notation. We're not going to do this today, but in theory, we could also chain together a scale and a rotation if we wanted 2. In this demo, we're only concerned about the translation, but we need to calculate the translation based on the x y value from the center point of the circle. We do that by taking the current translation value and then multiplying it by the cosine of the radians. That will give us the x value. And then to get the y value, we just take the sine of the radians. And even as a failed trigonometry student, I think I understand this. And that's all it takes to calculate that translation. The only other thing we have to do here is add a child widget which will just be a floating action button that will take our icon and background color arguments. Now we can come back up to the widget tree to our stack And just call this button for every item that we want to add to the menu. We'll put the first button at 0 degrees, the next one at 45, the next one at 90, and so on. If you open up the app, you should have an effect that looks like this. At this point, the buttons are going in and out, but there's no rotation going on yet. What I wanna show you is how to rotate the entire Widget stack But, do it in a way that's offset from the main animation timeline. This is what you would call a staggered animation. First, we'll set up another number tween And then we'll start at 0 and rotate around the entire circle to 360 degrees. We can make this staggered by going into the curved animation and then instead of providing a curve We'll provide an interval. This will tell the animation to start executing at a certain point in the animation timeline. With the first value being 0, that means the animation will start right away. But the second value is 0.7 which means it will end at 70% into the animation itself. In other words, the rotation animation will happen faster than the rest of the animation timeline. And now the interval itself will take the actual curve argument. So that takes care of the animation. Now let's come down to the widget tree then we'll wrap the entire stack in the transform rotate method. Now the stack will become the child of this widget and then we'll set the angle value to the rotation value. The angle is also based on radians, so you'll wanna do that conversion there if you're looking to do one full circle with 360 degrees. Now open up the demo on a device, and you should have the super smooth 60 frames per second animation. And if you don't believe me, Flutter has a built in profiler. So just run Flutter run flag profile and you should see that you have Plenty of room to spare for even more animation and UI painting. I'm gonna go ahead and wrap things up there. If you have any UI elements from popular mobile apps that you might want to see clone in this channel, let me know in the comments. And if this video helped you, please like and subscribe. Thanks for watching and I will talk to you soon.
Building
building
a
a
butter
butter
smooth
smooth
UI
ui
is
is
extremely
extremely
important
important
in
in
the
the
world
world
of
of
native
native
apps.
apps
It
it
only
only
takes
takes
a
a
small
small
amount
amount
of
of
jank
jank
for
for
people
people
to
to
think
think
your
your
app
app
sucks.
sucks
That's
that's
why
why
one
one
of
of
my
my
favorite
favorite
things
things
about
about
Flutter
flutter
is
is
how
how
beautifully
beautifully
it
it
renders
renders
the
the
animations.
animations
We
we
can
can
use
use
the
the
built
built
in
in
profiler
profiler
to
to
see
see
that
that
we
we
easily
easily
achieve
achieve
60
60
frames
frames
per
per
second
second
even
even
for
for
this
this
complex
complex
rotating
rotating
radio
radio
menu.
menu
In
in
today's
today's
video,
video
you'll
you'll
learn
learn
all
all
about
about
Flutter
flutter
animations
animations
by
by
building
building
this
this
menu
menu
Scratch.
scratch
If
if
you're
you're
new
new
here
here
like
like
and
and
subscribe
subscribe
and
and
you
you
can
can
find
find
the
the
full
full
source
source
code
code
on
on
Fireship
fireship
IO.
io
Before
before
we
we
get
get
started
started
I
i
have
have
a
a
confession
confession
to
to
make.
make
In
in
college
college
I
i
failed
failed
trigonometry.
trigonometry
I
i
vividly
vividly
remember
remember
Scoring
scoring
0
0
out
out
of
of
100
100
points
points
on
on
the
the
midterm
midterm
and
and
I
i
probably
probably
didn't
didn't
even
even
take
take
the
the
final.
final
And
and
that's
that's
not
not
good
good
because
because
we
we
need
need
to
to
use
use
trigonometry
trigonometry
in
in
this
this
video
video
to
to
determine
determine
where
where
to
to
place
place
the
the
different
different
elements
elements
on
on
the
the
menu.
menu
We
we
take
take
a
a
closer
closer
look
look
at
at
this
this
menu,
menu
we
we
actually
actually
have
have
10
10
different
different
buttons
buttons
stacked
stacked
on
on
top
top
of
of
each
each
other.
other
The
the
open
open
and
and
close
close
buttons
buttons
stay
stay
in
in
the
the
middle
middle
and
and
then
then
they
they
scale
scale
up
up
and
and
down
down
depending
depending
on
on
whether
whether
or
or
not
not
the
the
menu
menu
is
is
opened
opened
or
or
closed.
closed
When
when
opened,
opened
all
all
of
of
the
the
outer
outer
buttons
buttons
will
will
be
be
translated
translated
or
or
moved
moved
to
to
a
a
specific
specific
bearing
bearing
from
from
the
the
center
center
point.
point
This
this
is
is
where
where
trig
trig
comes
comes
into
into
play
play
because
because
we
we
need
need
to
to
calculate
calculate
a
a
specific
specific
x
x
y
y
coordinate
coordinate
based
based
on
on
an
an
angle
angle
from
from
the
the
center.
center
But
but
don't
don't
worry
worry
too
too
much
much
about
about
that.
that
It's
it's
actually
actually
a
a
very
very
easy
easy
calculation.
calculation
And
and
this
this
entire
entire
demo
demo
only
only
takes
takes
about
about
a
a
150
150
lines
lines
of
of
code,
code
which
which
is
is
pretty
pretty
crazy.
crazy
And
and
as
as
a
a
final
final
touch,
touch
we'll
we'll
also
also
add
add
a
a
rotation
rotation
to
to
the
the
entire
entire
stack
stack
of
of
buttons.
buttons
So
so
that
that
way,
way
it
it
rotates
rotates
clockwise
clockwise
when
when
opening
opening
and
and
counterclockwise
counterclockwise
when
when
closing.
closing
To
to
get
get
started,
started
you'll
you'll
need
need
to
to
have
have
a
a
Flutter
flutter
app,
app
and
and
then
then
I
i
also
also
have
have
vector
vector
math
math
installed
installed
and
and
optionally
optionally
Font
font
Awesome
awesome
for
for
some
some
better
better
icons
icons
in
in
the
the
material.
material
And
and
if
if
we
we
go
go
into
into
our
our
main
main
dart
dart
file,
file
you
you
can
can
see
see
that
that
I'm
i'm
importing
importing
dart
dart
math,
math
and
and
then
then
I'm
i'm
importing
importing
radians
radians
from
from
vector
vector
math.
math
And
and
it's
it's
important
important
to
to
do
do
the
the
import
import
like
like
this
this
because
because
it
it
has
has
some
some
conflicting
conflicting
classes
classes
with
with
Flutter.
flutter
Now
now
we'll
we'll
go
go
down
down
here
here
to
to
our
our
material
material
app,
app
and
and
we'll
we'll
just
just
add
add
a
a
scaffold.
scaffold
And
and
for
for
this
this
demo,
demo
we'll
we'll
just
just
have
have
the
the
menu
menu
fill
fill
up
up
the
the
entire
entire
screen.
screen
And
and
for
for
that,
that
we
we
can
can
use
use
a
a
sized
sized
box
box
and
and
have
have
it
it
expand
expand
to
to
fill
fill
out
out
the
the
entire
entire
viewport.
viewport
And
and
then
then
the
the
child
child
for
for
that
that
box
box
will
will
be
be
our
our
custom
custom
radial
radial
menu
menu
widget.
widget
When
when
working
working
with
with
animations,
animations
the
the
first
first
thing
thing
you'll
you'll
usually
usually
start
start
with
with
is
is
a
a
Stateful
stateful
widget.
widget
The
the
only
only
thing
thing
this
this
widget
widget
is
is
concerned
concerned
with
with
is
is
defining
defining
the
the
animation
animation
controller,
controller
which
which
itself
itself
controls
controls
the
the
duration
duration
of
of
the
the
animation
animation
as
as
well
well
as
as
the
the
controls
controls
is
is
to
to
tell
tell
it
it
to
to
play
play
in
in
forward
forward
or
or
in
in
reverse.
reverse
What
what
it
it
doesn't
doesn't
control
control
is
is
the
the
actual
actual
animation
animation
properties
properties
or
or
the
the
UI
ui
elements
elements
that
that
are
are
being
being
animated.
animated
First
first
thing
thing
we'll
we'll
do
do
is
is
add
add
a
a
mix
mix
into
into
this
this
class
class
called
called
the
the
single
single
ticker
ticker
provider
provider
state
state
mix
mix
in.
in
This
this
will
will
put
put
the
the
widget
widget
in
in
ticker
ticker
mode,
mode
which
which
makes
makes
animations
animations
possible.
possible
The
the
next
next
thing
thing
we'll
we'll
do
do
is
is
declare
declare
our
our
animation
animation
controller
controller
and
and
then
then
we'll
we'll
actually
actually
define
define
it
it
inside
inside
of
of
the
the
init
init
lifecycle
lifecycle
hook.
hook
The
the
most
most
important
important
aspect
aspect
of
of
the
the
animation
animation
controller
controller
is
is
the
the
duration.
duration
At
at
the
the
end
end
of
of
the
the
video,
video
we'll
we'll
stagger
stagger
animations,
animations
which
which
will
will
all
all
be
be
relative
relative
to
to
the
the
duration
duration
that
that
we
we
define
define
here.
here
So
so
in
in
this
this
case,
case
the
the
total
total
duration
duration
of
of
the
the
animation
animation
is
is
900
900
milliseconds.
milliseconds
We
we
also
also
have
have
to
to
pass
pass
the
the
this
this
context
context
to
to
v
v
sync,
sync
which
which
is
is
just
just
a
a
piece
piece
of
of
boilerplate
boilerplate
for
for
animation
animation
controllers.
controllers
In
in
order
order
to
to
achieve
achieve
60
60
frames
frames
per
per
2nd,
2nd
this
this
animation
animation
controller
controller
will
will
tick
tick
every
every
16
16
milliseconds.
milliseconds
I
i
have
have
it
it
commented
commented
out
out
here,
here
but
but
you
you
could
could
add
add
a
a
listener
listener
to
to
this
this
controller
controller
and
and
then
then
set
set
the
the
state
state
every
every
time
time
it
it
ticks.
ticks
But
but
we'll
we'll
be
be
using
using
an
an
animated
animated
builder
builder
in
in
the
the
next
next
step,
step
which
which
makes
makes
this
this
part
part
unnecessary.
unnecessary
Now
now
we'll
we'll
define
define
the
the
build
build
method
method
for
for
this
this
widget,
widget
and
and
you'll
you'll
see
see
it
it
returns
returns
a
a
radial
radial
animation
animation
widget,
widget
which
which
we'll
we'll
define
define
next.
next
Just
just
notice
notice
how
how
it
it
takes
takes
the
the
animation
animation
controller
controller
as
as
a
a
property
property
to
to
its
its
constructor.
constructor
We'll
we'll
be
be
using
using
the
the
same
same
controller
controller
to
to
orchestrate
orchestrate
multiple
multiple
different
different
animations
animations
at
at
the
the
same
same
time.
time
All
all
of
of
the
the
animation
animation
logic
logic
will
will
be
be
handled
handled
by
by
this
this
radial
radial
animation
animation
widget.
widget
In
in
order
order
for
for
it
it
to
to
take
take
the
the
animation
animation
controller
controller
as
as
an
an
input
input
property,
property
we
we
add
add
it
it
to
to
the
the
constructor
constructor
here
here
and
and
then
then
call
call
super.
super
From
from
there,
there
we'll
we'll
define
define
the
the
build
build
method,
method
and
and
it
it
will
will
start
start
with
with
an
an
animated
animated
builder.
builder
An
an
animated
animated
builder
builder
takes
takes
2
2
main
main
arguments.
arguments
The
the
first
first
one
one
is
is
just
just
the
the
animation
animation
controller,
controller
And
and
the
the
second
second
one
one
is
is
a
a
function
function
to
to
build
build
the
the
UI.
ui
So,
so
basically,
basically
every
every
time
time
the
the
animation
animation
controller
controller
ticks,
ticks
it
it
will
will
run
run
this
this
builder
builder
function
function
to
to
rebuild
rebuild
all
all
your
your
widgets.
widgets
We
we
can
can
control
control
the
the
state
state
of
of
this
this
animation
animation
both
both
in
in
the
the
stateless
stateless
widget
widget
or
or
in
in
the
the
stateful
stateful
widget
widget
above.
above
Because
because
this
this
is
is
a
a
menu,
menu
I
i
wanna
wanna
make
make
these
these
methods
methods
a
a
little
little
more
more
clear,
clear
so
so
I'm
i'm
defining
defining
my
my
own
own
custom
custom
methods
methods
called
called
open
open
and
and
close.
close
Open
open
will
will
run
run
the
the
animation
animation
in
in
forward
forward
and
and
then
then
close
close
will
will
run
run
the
the
animation
animation
in
in
reverse.
reverse
Now
now
we
we
can
can
go
go
up
up
to
to
our
our
builder
builder
function,
function
and
and
the
the
first
first
thing
thing
I'm
i'm
going
going
to
to
define
define
is
is
a
a
stack
stack
because,
because
remember,
remember
all
all
the
the
buttons
buttons
are
are
just
just
stacked
stacked
on
on
top
top
of
of
each
each
other.
other
In
in
the
the
children
children
array,
array
I'll
i'll
go
go
ahead
ahead
and
and
add
add
2
2
floating
floating
action
action
buttons.
buttons
And
and
because
because
we're
we're
working
working
with
with
a
a
stack,
stack
only
only
the
the
last
last
button
button
should
should
be
be
visible.
visible
That
that
means
means
you
you
want
want
the
the
button
button
that
that
will
will
open
open
the
the
menu
menu
initially
initially
to
to
be
be
the
the
last
last
item
item
in
in
the
the
stack.
stack
If
if
we
we
open
open
this
this
on
on
a
a
device,
device
we
we
should
should
see
see
our
our
blue
blue
open
open
menu
menu
button.
button
And
and
if
if
we
we
take
take
that
that
out
out
of
of
the
the
stack,
stack
then
then
we'll
we'll
see
see
the
the
close
close
button.
button
That
that
takes
takes
care
care
of
of
the
the
initial
initial
setup.
setup
Now
now
let's
let's
build
build
the
the
first
first
animation
animation
that
that
toggles
toggles
this
this
open
open
and
and
close
close
button.
button
For
for
that,
that
we're
we're
going
going
to
to
zoom
zoom
out
out
a
a
bit
bit
and
and
go
go
to
to
the
the
top
top
of
of
our
our
radial
radial
animation
animation
button
button
and
and
first
first
define
define
a
a
property
property
called
called
scale
scale
that
that
is
is
typed
typed
to
to
an
an
animation
animation
of
of
a
a
number.
number
Then
then
we'll
we'll
define
define
scale
scale
as
as
a
a
tween.
tween
A
a
tween
tween
is
is
one
one
of
of
those
those
words
words
that
that
always
always
makes
makes
me
me
nervous
nervous
when
when
I
i
see
see
it.
it
However,
however
they're
they're
actually
actually
very
very
simple,
simple
and
and
they
they
just
just
translate
translate
to
to
in
in
between.
between
So
so
you
you
give
give
it
it
a
a
starting
starting
value
value
and
and
an
an
ending
ending
value,
value
and
and
it
it
will
will
calculate
calculate
everything
everything
in
in
between.
between
In
in
this
this
case,
case
we're
we're
animating
animating
the
the
scale
scale
of
of
an
an
element.
element
By
by
giving
giving
it
it
a
a
starting
starting
point
point
of
of
1.5,
1.5
it
it
will
will
be
be
150%
150%
of
of
its
its
normal
normal
size.
size
And
and
then
then
at
at
the
the
end
end
of
of
the
the
animation,
animation
it
it
will
will
be
be
0%
0%
or
or
invisible.
invisible
The
the
next
next
thing
thing
we
we
need
need
to
to
do
do
is
is
bind
bind
this
this
tween
tween
to
to
our
our
actual
actual
animation
animation
controller.
controller
That
that
gives
gives
it
it
an
an
actual
actual
duration
duration
to
to
know
know
how
how
to
to
calculate
calculate
the
the
in
in
between
between
values.
values
You
you
could
could
just
just
pass
pass
in
in
the
the
animation
animation
controller
controller
directly
directly
here,
here
but
but
more
more
often
often
than
than
not,
not
you'll
you'll
use
use
a
a
curved
curved
animation
animation
to
to
make
make
your
your
animations
animations
a
a
little
little
more
more
exciting.
exciting
I'm
i'm
using
using
fast
fast
out
out
slow
slow
in,
in
but
but
there's
there's
a
a
lot
lot
of
of
different
different
curves
curves
you
you
can
can
experiment
experiment
with
with
here.
here
The
the
last
last
piece
piece
of
of
this
this
puzzle
puzzle
is
is
determining
determining
where
where
to
to
apply
apply
this
this
animation
animation
in
in
the
the
widget
widget
tree.
tree
The
the
scale
scale
animation
animation
is
is
only
only
going
going
to
to
apply
apply
to
to
our
our
open
open
and
and
close
close
buttons
buttons
in
in
the
the
middle.
middle
Flutter
flutter
has
has
this
this
super
super
useful
useful
thing
thing
called
called
a
a
transform
transform
widget,
widget
And
and
it
it
has
has
a
a
few
few
static
static
methods
methods
to
to
rotate,
rotate
scale,
scale
and
and
translate
translate
a
a
child
child
widget,
widget
but
but
it
it
can
can
also
also
be
be
used
used
for
for
super
super
complex
complex
perspective
perspective
based
based
3
3
d
d
animations.
animations
So
so
notice
notice
here
here
how
how
we
we
wrapped
wrapped
our
our
floating
floating
action
action
button
button
in
in
the
the
transform
transform
scale.
scale
And
and
then
then
for
for
the
the
scale
scale
argument,
argument
we're
we're
passing
passing
at
at
the
the
scale
scale
value
value
from
from
the
the
tween
tween
animation.
animation
So
so
that
that
means
means
every
every
animation
animation
tick
tick
or
or
every
every
16
16
milliseconds,
milliseconds
it
it
will
will
update
update
the
the
scale
scale
value
value
of
of
this
this
element
element
when
when
it's
it's
animating.
animating
Now,
now
we'll
we'll
go
go
ahead
ahead
and
and
wrap
wrap
the
the
other
other
button
button
in
in
Transform
transform
Scale
scale
as
as
well.
well
But
but
you'll
you'll
notice
notice
right
right
now
now
they're
they're
both
both
using
using
the
the
same
same
animation,
animation
so
so
they'll
they'll
be
be
doing
doing
the
the
same
same
thing
thing
at
at
the
the
same
same
time.
time
We
we
could
could
write
write
an
an
entirely
entirely
different
different
animation
animation
for
for
each
each
button,
button
but
but
we
we
can
can
also
also
be
be
kind
kind
of
of
clever
clever
here
here
and
and
instead
instead
just
just
subtract
subtract
1
1
from
from
the
the
scale
scale
value,
value
which
which
will
will
give
give
us
us
the
the
opposite
opposite
animation
animation
for
for
the
the
closing
closing
button.
button
Always
always
see
see
if
if
you
you
can
can
be
be
clever
clever
first
first
before
before
writing
writing
a
a
bunch
bunch
of
of
extra
extra
code.
code
That
that
completes
completes
the
the
first
first
animation.
animation
If
if
we
we
open
open
it
it
up
up
on
on
a
a
device,
device
we
we
should
should
see
see
the
the
button
button
scaling
scaling
in
in
and
and
out
out
when
when
clicked.
clicked
The
the
next
next
challenge
challenge
is
is
to
to
create
create
a
a
whole
whole
bunch
bunch
of
of
buttons
buttons
that
that
pop
pop
out
out
of
of
the
the
middle
middle
when
when
the
the
menu
menu
is
is
activated.
activated
We'll
we'll
go
go
back
back
up
up
to
to
the
the
constructor
constructor
and
and
add
add
another
another
animation
animation
that's
that's
very
very
similar
similar
to
to
our
our
scale
scale
animation.
animation
This
this
time,
time
we'll
we'll
go
go
ahead
ahead
and
and
call
call
it
it
translation.
translation
We'll
we'll
give
give
it
it
a
a
starting
starting
value
value
of
of
0
0
and
and
an
an
ending
ending
value
value
of
of
100.
100
Then
then
we'll
we'll
define
define
a
a
curved
curved
animation.
animation
Then,
then
again,
again
make
make
sure
sure
to
to
experiment
experiment
with
with
the
the
different
different
curves.
curves
You
you
have
have
a
a
whole
whole
bunch
bunch
of
of
different
different
options
options
here.
here
Now
now
we
we
definitely
definitely
don't
don't
want
want
to
to
hard
hard
code
code
a
a
bunch
bunch
of
of
floating
floating
action
action
buttons
buttons
1
1
by
by
1.
1
Instead,
instead
I'm
i'm
writing
writing
a
a
method
method
called
called
build
build
button
button
which
which
will
will
take
take
an
an
angle
angle
as
as
an
an
argument
argument
which
which
is
is
in
in
degrees
degrees
and
and
then
then
it
it
will
will
also
also
take
take
an
an
optional
optional
color
color
and
and
icon.
icon
This
this
This
this
is
is
the
the
part
part
where
where
a
a
little
little
bit
bit
of
of
trigonometry
trigonometry
is
is
going
going
to
to
help
help
us
us
write
write
very
very
concise
concise
code.
code
What
what
we
we
wanna
wanna
do
do
is
is
translate
translate
each
each
individual
individual
button
button
at
at
a
a
specific
specific
angle
angle
from
from
the
the
center
center
point
point
of
of
this
this
menu.
menu
This
this
needs
needs
to
to
be
be
done
done
in
in
radians
radians
and
and
not
not
degrees,
degrees
but
but
degrees
degrees
are
are
a
a
lot
lot
easier
easier
to
to
work
work
with
with
if
if
you're
you're
a
a
human
human
being
being
because
because
it's
it's
easy
easy
to
to
reason
reason
about
about
a
a
circle
circle
when
when
you
you
think
think
of
of
it
it
in
in
360
360
degrees.
degrees
The
the
first
first
thing
thing
we'll
we'll
do
do
is
is
convert
convert
that
that
angle
angle
argument
argument
to
to
radians.
radians
Then
then
we'll
we'll
define
define
a
a
transform
transform
widget.
widget
And
and
that
that
allows
allows
us
us
to
to
actually
actually
pass
pass
in
in
a
a
transformation
transformation
matrix.
matrix
This
this
is
is
really
really
cool
cool
because
because
you
you
can
can
chain
chain
together
together
different
different
transformations
transformations
by
by
using
using
Dart's
dart's
double
double
dot
dot
notation.
notation
We're
we're
not
not
going
going
to
to
do
do
this
this
today,
today
but
but
in
in
theory,
theory
we
we
could
could
also
also
chain
chain
together
together
a
a
scale
scale
and
and
a
a
rotation
rotation
if
if
we
we
wanted
wanted
2.
2
In
in
this
this
demo,
demo
we're
we're
only
only
concerned
concerned
about
about
the
the
translation,
translation
but
but
we
we
need
need
to
to
calculate
calculate
the
the
translation
translation
based
based
on
on
the
the
x
x
y
y
value
value
from
from
the
the
center
center
point
point
of
of
the
the
circle.
circle
We
we
do
do
that
that
by
by
taking
taking
the
the
current
current
translation
translation
value
value
and
and
then
then
multiplying
multiplying
it
it
by
by
the
the
cosine
cosine
of
of
the
the
radians.
radians
That
that
will
will
give
give
us
us
the
the
x
x
value.
value
And
and
then
then
to
to
get
get
the
the
y
y
value,
value
we
we
just
just
take
take
the
the
sine
sine
of
of
the
the
radians.
radians
And
and
even
even
as
as
a
a
failed
failed
trigonometry
trigonometry
student,
student
I
i
think
think
I
i
understand
understand
this.
this
And
and
that's
that's
all
all
it
it
takes
takes
to
to
calculate
calculate
that
that
translation.
translation
The
the
only
only
other
other
thing
thing
we
we
have
have
to
to
do
do
here
here
is
is
add
add
a
a
child
child
widget
widget
which
which
will
will
just
just
be
be
a
a
floating
floating
action
action
button
button
that
that
will
will
take
take
our
our
icon
icon
and
and
background
background
color
color
arguments.
arguments
Now
now
we
we
can
can
come
come
back
back
up
up
to
to
the
the
widget
widget
tree
tree
to
to
our
our
stack
stack
And
and
just
just
call
call
this
this
button
button
for
for
every
every
item
item
that
that
we
we
want
want
to
to
add
add
to
to
the
the
menu.
menu
We'll
we'll
put
put
the
the
first
first
button
button
at
at
0
0
degrees,
degrees
the
the
next
next
one
one
at
at
45,
45
the
the
next
next
one
one
at
at
90,
90
and
and
so
so
on.
on
If
if
you
you
open
open
up
up
the
the
app,
app
you
you
should
should
have
have
an
an
effect
effect
that
that
looks
looks
like
like
this.
this
At
at
this
this
point,
point
the
the
buttons
buttons
are
are
going
going
in
in
and
and
out,
out
but
but
there's
there's
no
no
rotation
rotation
going
going
on
on
yet.
yet
What
what
I
i
wanna
wanna
show
show
you
you
is
is
how
how
to
to
rotate
rotate
the
the
entire
entire
Widget
widget
stack
stack
But,
but
do
do
it
it
in
in
a
a
way
way
that's
that's
offset
offset
from
from
the
the
main
main
animation
animation
timeline.
timeline
This
this
is
is
what
what
you
you
would
would
call
call
a
a
staggered
staggered
animation.
animation
First,
first
we'll
we'll
set
set
up
up
another
another
number
number
tween
tween
And
and
then
then
we'll
we'll
start
start
at
at
0
0
and
and
rotate
rotate
around
around
the
the
entire
entire
circle
circle
to
to
360
360
degrees.
degrees
We
we
can
can
make
make
this
this
staggered
staggered
by
by
going
going
into
into
the
the
curved
curved
animation
animation
and
and
then
then
instead
instead
of
of
providing
providing
a
a
curve
curve
We'll
we'll
provide
provide
an
an
interval.
interval
This
this
will
will
tell
tell
the
the
animation
animation
to
to
start
start
executing
executing
at
at
a
a
certain
certain
point
point
in
in
the
the
animation
animation
timeline.
timeline
With
with
the
the
first
first
value
value
being
being
0,
0
that
that
means
means
the
the
animation
animation
will
will
start
start
right
right
away.
away
But
but
the
the
second
second
value
value
is
is
0.7
0.7
which
which
means
means
it
it
will
will
end
end
at
at
70%
70%
into
into
the
the
animation
animation
itself.
itself
In
in
other
other
words,
words
the
the
rotation
rotation
animation
animation
will
will
happen
happen
faster
faster
than
than
the
the
rest
rest
of
of
the
the
animation
animation
timeline.
timeline
And
and
now
now
the
the
interval
interval
itself
itself
will
will
take
take
the
the
actual
actual
curve
curve
argument.
argument
So
so
that
that
takes
takes
care
care
of
of
the
the
animation.
animation
Now
now
let's
let's
come
come
down
down
to
to
the
the
widget
widget
tree
tree
then
then
we'll
we'll
wrap
wrap
the
the
entire
entire
stack
stack
in
in
the
the
transform
transform
rotate
rotate
method.
method
Now
now
the
the
stack
stack
will
will
become
become
the
the
child
child
of
of
this
this
widget
widget
and
and
then
then
we'll
we'll
set
set
the
the
angle
angle
value
value
to
to
the
the
rotation
rotation
value.
value
The
the
angle
angle
is
is
also
also
based
based
on
on
radians,
radians
so
so
you'll
you'll
wanna
wanna
do
do
that
that
conversion
conversion
there
there
if
if
you're
you're
looking
looking
to
to
do
do
one
one
full
full
circle
circle
with
with
360
360
degrees.
degrees
Now
now
open
open
up
up
the
the
demo
demo
on
on
a
a
device,
device
and
and
you
you
should
should
have
have
the
the
super
super
smooth
smooth
60
60
frames
frames
per
per
second
second
animation.
animation
And
and
if
if
you
you
don't
don't
believe
believe
me,
me
Flutter
flutter
has
has
a
a
built
built
in
in
profiler.
profiler
So
so
just
just
run
run
Flutter
flutter
run
run
flag
flag
profile
profile
and
and
you
you
should
should
see
see
that
that
you
you
have
have
Plenty
plenty
of
of
room
room
to
to
spare
spare
for
for
even
even
more
more
animation
animation
and
and
UI
ui
painting.
painting
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
If
if
you
you
have
have
any
any
UI
ui
elements
elements
from
from
popular
popular
mobile
mobile
apps
apps
that
that
you
you
might
might
want
want
to
to
see
see
clone
clone
in
in
this
this
channel,
channel
let
let
me
me
know
know
in
in
the
the
comments.
comments
And
and
if
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
subscribe.
subscribe
Thanks
thanks
for
for
watching
watching
and
and
I
i
will
will
talk
talk
to
to
you
you
soon.
soon
success
The importance of building a butter-ish UI for native apps, including Flutter, vector math, and a roofing component, is emphasized. A tutorial on building a Flutter app and vector math installation is provided, along with a guide on creating a Flutter app and vector math installation. The process of creating a widget for an animation controller, including the duration, build method, and use of a radial animation widget, is discussed, along with the use of a transform widget and a transformation matrix. The importance of avoiding rotation and creating a staggered animation is emphasized, along with the use of a transparent animation for multiple buttons and the transformation of angle to transformation.
Flutter Animation -  Radial Menu at 60FPS
Building a butter smooth UI is extremely important in the world of native apps. It only takes a small amount of jank for people to think your app sucks. That's why one of my favorite things about Flutter is how beautifully it renders the animations. We can use the built in profiler to see that we easily achieve 60 frames per second even for this complex rotating radio menu. In today's video, you'll learn all about Flutter animations by building this menu Scratch. If you're new here like and subscribe and you can find the full source code on Fireship IO. Before we get started I have a confession to make. In college I failed trigonometry. I vividly remember Scoring 0 out of 100 points on the midterm and I probably didn't even take the final. And that's not good because we need to use trigonometry in this video to determine where to place the different elements on the menu. We take a closer look at this menu, we actually have 10 different buttons stacked on top of each other. The open and close buttons stay in the middle and then they scale up and down depending on whether or not the menu is opened or closed. When opened, all of the outer buttons will be translated or moved to a specific bearing from the center point. This is where trig comes into play because we need to calculate a specific x y coordinate based on an angle from the center. But don't worry too much about that. It's actually a very easy calculation. And this entire demo only takes about a 150 lines of code, which is pretty crazy. And as a final touch, we'll also add a rotation to the entire stack of buttons. So that way, it rotates clockwise when opening and counterclockwise when closing. To get started, you'll need to have a Flutter app, and then I also have vector math installed and optionally Font Awesome for some better icons in the material. And if we go into our main dart file, you can see that I'm importing dart math, and then I'm importing radians from vector math. And it's important to do the import like this because it has some conflicting classes with Flutter. Now we'll go down here to our material app, and we'll just add a scaffold. And for this demo, we'll just have the menu fill up the entire screen. And for that, we can use a sized box and have it expand to fill out the entire viewport. And then the child for that box will be our custom radial menu widget. When working with animations, the first thing you'll usually start with is a Stateful widget. The only thing this widget is concerned with is defining the animation controller, which itself controls the duration of the animation as well as the controls is to tell it to play in forward or in reverse. What it doesn't control is the actual animation properties or the UI elements that are being animated. First thing we'll do is add a mix into this class called the single ticker provider state mix in. This will put the widget in ticker mode, which makes animations possible. The next thing we'll do is declare our animation controller and then we'll actually define it inside of the init lifecycle hook. The most important aspect of the animation controller is the duration. At the end of the video, we'll stagger animations, which will all be relative to the duration that we define here. So in this case, the total duration of the animation is 900 milliseconds. We also have to pass the this context to v sync, which is just a piece of boilerplate for animation controllers. In order to achieve 60 frames per 2nd, this animation controller will tick every 16 milliseconds. I have it commented out here, but you could add a listener to this controller and then set the state every time it ticks. But we'll be using an animated builder in the next step, which makes this part unnecessary. Now we'll define the build method for this widget, and you'll see it returns a radial animation widget, which we'll define next. Just notice how it takes the animation controller as a property to its constructor. We'll be using the same controller to orchestrate multiple different animations at the same time. All of the animation logic will be handled by this radial animation widget. In order for it to take the animation controller as an input property, we add it to the constructor here and then call super. From there, we'll define the build method, and it will start with an animated builder. An animated builder takes 2 main arguments. The first one is just the animation controller, And the second one is a function to build the UI. So, basically, every time the animation controller ticks, it will run this builder function to rebuild all your widgets. We can control the state of this animation both in the stateless widget or in the stateful widget above. Because this is a menu, I wanna make these methods a little more clear, so I'm defining my own custom methods called open and close. Open will run the animation in forward and then close will run the animation in reverse. Now we can go up to our builder function, and the first thing I'm going to define is a stack because, remember, all the buttons are just stacked on top of each other. In the children array, I'll go ahead and add 2 floating action buttons. And because we're working with a stack, only the last button should be visible. That means you want the button that will open the menu initially to be the last item in the stack. If we open this on a device, we should see our blue open menu button. And if we take that out of the stack, then we'll see the close button. That takes care of the initial setup. Now let's build the first animation that toggles this open and close button. For that, we're going to zoom out a bit and go to the top of our radial animation button and first define a property called scale that is typed to an animation of a number. Then we'll define scale as a tween. A tween is one of those words that always makes me nervous when I see it. However, they're actually very simple, and they just translate to in between. So you give it a starting value and an ending value, and it will calculate everything in between. In this case, we're animating the scale of an element. By giving it a starting point of 1.5, it will be 150% of its normal size. And then at the end of the animation, it will be 0% or invisible. The next thing we need to do is bind this tween to our actual animation controller. That gives it an actual duration to know how to calculate the in between values. You could just pass in the animation controller directly here, but more often than not, you'll use a curved animation to make your animations a little more exciting. I'm using fast out slow in, but there's a lot of different curves you can experiment with here. The last piece of this puzzle is determining where to apply this animation in the widget tree. The scale animation is only going to apply to our open and close buttons in the middle. Flutter has this super useful thing called a transform widget, And it has a few static methods to rotate, scale, and translate a child widget, but it can also be used for super complex perspective based 3 d animations. So notice here how we wrapped our floating action button in the transform scale. And then for the scale argument, we're passing at the scale value from the tween animation. So that means every animation tick or every 16 milliseconds, it will update the scale value of this element when it's animating. Now, we'll go ahead and wrap the other button in Transform Scale as well. But you'll notice right now they're both using the same animation, so they'll be doing the same thing at the same time. We could write an entirely different animation for each button, but we can also be kind of clever here and instead just subtract 1 from the scale value, which will give us the opposite animation for the closing button. Always see if you can be clever first before writing a bunch of extra code. That completes the first animation. If we open it up on a device, we should see the button scaling in and out when clicked. The next challenge is to create a whole bunch of buttons that pop out of the middle when the menu is activated. We'll go back up to the constructor and add another animation that's very similar to our scale animation. This time, we'll go ahead and call it translation. We'll give it a starting value of 0 and an ending value of 100. Then we'll define a curved animation. Then, again, make sure to experiment with the different curves. You have a whole bunch of different options here. Now we definitely don't want to hard code a bunch of floating action buttons 1 by 1. Instead, I'm writing a method called build button which will take an angle as an argument which is in degrees and then it will also take an optional color and icon. This This is the part where a little bit of trigonometry is going to help us write very concise code. What we wanna do is translate each individual button at a specific angle from the center point of this menu. This needs to be done in radians and not degrees, but degrees are a lot easier to work with if you're a human being because it's easy to reason about a circle when you think of it in 360 degrees. The first thing we'll do is convert that angle argument to radians. Then we'll define a transform widget. And that allows us to actually pass in a transformation matrix. This is really cool because you can chain together different transformations by using Dart's double dot notation. We're not going to do this today, but in theory, we could also chain together a scale and a rotation if we wanted 2. In this demo, we're only concerned about the translation, but we need to calculate the translation based on the x y value from the center point of the circle. We do that by taking the current translation value and then multiplying it by the cosine of the radians. That will give us the x value. And then to get the y value, we just take the sine of the radians. And even as a failed trigonometry student, I think I understand this. And that's all it takes to calculate that translation. The only other thing we have to do here is add a child widget which will just be a floating action button that will take our icon and background color arguments. Now we can come back up to the widget tree to our stack And just call this button for every item that we want to add to the menu. We'll put the first button at 0 degrees, the next one at 45, the next one at 90, and so on. If you open up the app, you should have an effect that looks like this. At this point, the buttons are going in and out, but there's no rotation going on yet. What I wanna show you is how to rotate the entire Widget stack But, do it in a way that's offset from the main animation timeline. This is what you would call a staggered animation. First, we'll set up another number tween And then we'll start at 0 and rotate around the entire circle to 360 degrees. We can make this staggered by going into the curved animation and then instead of providing a curve We'll provide an interval. This will tell the animation to start executing at a certain point in the animation timeline. With the first value being 0, that means the animation will start right away. But the second value is 0.7 which means it will end at 70% into the animation itself. In other words, the rotation animation will happen faster than the rest of the animation timeline. And now the interval itself will take the actual curve argument. So that takes care of the animation. Now let's come down to the widget tree then we'll wrap the entire stack in the transform rotate method. Now the stack will become the child of this widget and then we'll set the angle value to the rotation value. The angle is also based on radians, so you'll wanna do that conversion there if you're looking to do one full circle with 360 degrees. Now open up the demo on a device, and you should have the super smooth 60 frames per second animation. And if you don't believe me, Flutter has a built in profiler. So just run Flutter run flag profile and you should see that you have Plenty of room to spare for even more animation and UI painting. I'm gonna go ahead and wrap things up there. If you have any UI elements from popular mobile apps that you might want to see clone in this channel, let me know in the comments. And if this video helped you, please like and subscribe. Thanks for watching and I will talk to you soon.
The importance of building a butter-ish UI for native apps, including Flutter, vector math, and a roofing component, is emphasized. A tutorial on building a Flutter app and vector math installation is provided, along with a guide on creating a Flutter app and vector math installation. The process of creating a widget for an animation controller, including the duration, build method, and use of a radial animation widget, is discussed, along with the use of a transform widget and a transformation matrix. The importance of avoiding rotation and creating a staggered animation is emphasized, along with the use of a transparent animation for multiple buttons and the transformation of angle to transformation.