
In a world where your app is competing with millions of others, it's important for it to stand out visually as much as functionally. Sprinkling some beautiful animations across your app can really enhance its appeal and the user’s overall experience.
SVGs are incredibly versatile, customizable, and can be animated inside of your apps for a unique effect. Rive, formerly known as Flare, is an animation software that can be used to easily create animated SVGs. The Rive Flutter package can then be used to seamlessly add the animations you create into your apps.
The Finished App
In this tutorial we are going to learn several things. First, we’ll get familiarized with the essentials of the Rive editor and learn how you can create your very own animations. We will then create a UI focused app where we will include several animations created with Rive using the Flutter Rive package.
Our finished app will be a minimalistic representation of a music player UI. It will have a splash screen with an animated radio that will be briefly visible before the main page loads. The main page of the app will have music player controls that will display animations when they're tapped. The play/pause button will display an animation that uses a State Machine that allows you to display a specific animation based on certain conditions. This button also plays and pauses a sound wave animation that's located below the music player controls.
Though it is simple, going through the development of this project will give you all the tools you need to start creating your very own animations and adding them to your Flutter apps. You will also have enough confidence to explore further and master all of the advanced functionalities that Rive has to offer.
Getting Started

Formerly, Rive was known as Flare which has its own Flutter package, Flare-Flutter. We will be working with the latest version of both the software and the package. This is important as there is a lot of material online about Flare-Flutter and not so much about the new Rive package which has a different syntax. On top of this, the old Flare software doesn’t allow any new sign-ups and new users are mandated to use Rive instead. So, wether you're new to Rive or want to switch from Flare, this tutorial will help you make a seamless entrance or transition.
We will be using a starter project in this tutorial which contains all of the Rive files we will use in the app. So, be sure to grab it from the link below if you would like to follow along.
The only package we'll be using here will be Rive, so let’s go ahead and add it as a dependency to our project now. At the time of writing this tutorial the current version is 0.7.28 and it is actively maintained and managed by the Rive team.
pubspec.yaml
dependencies:
flutter:
sdk: flutter
rive: ^0.7.28
Starter Project Overview
The starter project for this tutorial is very simple. It contains only three files in the lib folder - main.dart, music_player_page.dart, and splash_screen.dart. The main.dart file contains anAppWidget
which is configured to display the SplashScreen
. The SplashScreen
is a stateful widget that just has a Scaffold
with a custom background color. The music_player_page.dart holds a stateful MusicPlayerPage
widget which contains a Scaffold
with a centered Column
. Inside the Column
is an image of an album cover to go with our music player theme.
As you can tell, the starter project files are pretty bare-boned. That is because the majority of our project will consist of animated SVGs which we will add during the tutorial. Rive allows you to download files in the riv format from their editor. These files contain all the data you need to add the animations to your app. Even though we will go over the basics of creating your own animations, we also included some pre-made animations in the assets folder of the starter project. These files will be used to create the finished project.

Rive Editor Fundamentals
The goal of this tutorial is to provide enough knowledge for you to be able to create your own animations and then add them into your Flutter apps. That is why before we move on to coding, we'll learn some Rive editor fundamentals. So, if you don’t already have a Rive account, go to www.rive.app and create one now.

Dashboard
Once you’re logged in you will be taken to your account dashboard. Here you can see all of your files, create new files, and folders. Go ahead and create a new file.

Editor Overview - Design Mode

When you create a new file, you will be prompted to create an artboard and define its dimensions. Go ahead and click “Create”, leaving the default dimensions. Now you should have your new file opened in the editor with a new 500x500 artboard. You can also change the artboard size inside the editor.

When you create a file, you will be in Design mode. You can switch between Design and Animate modes in the editor. In Design mode you can create your graphics, import SVGs created in software such as Adobe Illustrator and edit them to your liking.
In the top bar of the editor, you can click on the “+” symbol to do things like create shapes, paths, additional artboards, bones, and groups. Let’s add a star shape to our artboard with dimensions of 200x200. Select the star shape then click and drag on the artboard until the star is of the desired dimensions. You can also adjust the dimensions in the right sidebar.
When you click on the shape, you'll see a circle with two arrows pointing to the x and y axis. You can use the arrows and the box surrounding the star to scale and rotate the shape. If you're interested in precise editing, you may find it more useful to change these and other shape properties using the sidebar on the right. If you ever used software similar to Adobe Illustrator, the settings in the sidebar should look really familiar.
Make sure the star shape is selected and go to the sidebar to change the fill color for it. We are using the following color code FFC000 to make the star yellow. Let’s also add a black-colored stroke to the star with a thickness of 4. That's all of the designing we are going to do for this simple demonstration.
Editor Overview - Animate Mode
Now, let’s move over to the Animate mode. When you switch to animate mode, the layout of the editor will stay pretty much the same, except a timeline will appear at the bottom. In this mode you create one or more animations by changing different shape/layer properties and adding keyframes for the respective changes to the timeline.
Double-click on the name of the existing animation to the left of the timeline and rename it to “Rotation”. Name your animations thoughtfully, because these will be the same names you'll use to add the animations to your code.
By clicking on the time to the left of the timeline, you can change things like the duration and playback speed of your animation. We are going to leave everything here untouched for this demonstration.

Creating Our First Animation - Rotation
Now, let’s make our star rotate 360°. Select the star, set the playhead to the beginning of the timeline, then making sure that the rotation is at 0° click on the rhombus next to the rotation setting.
You just created your first keyframe that will represent the starting point for the rotation. Now, move the playhead over to the very end of the timeline, double click on the rotation number, change it to 360°, and press enter. You should now see another keyframe at the end of the timeline. Now when the animation plays it will rotate the star from 0° to 360°. To see this animation, bring the playhead back to the beginning of the timeline and click the play button.
Right now the animation only runs once. To see it again, bring the playhead to the beginning of the timeline, and then hit play again. If you click on the right pointing arrow to the right of the play button, you can make the animation loop or ping pong (go back and forth in a loop). We are going to leave this as a one shot animation.

Creating Our Second Animation - Scale
Let’s add one more animation for the star to make it scale down and then back up. Click on the “+” symbol in the Animations panel to the left to the timeline and add an animation. Rename the animation to “Scale”.
Now, select your newly created animation, then select the star and make sure the playhead is at the beginning of the timeline. Click on the rhombus next to the X axis and the one next to the Y axis of the scale setting in the sidebar to set the initial keyframe to 100% scale.
Next, move the playhead over to 30f in the timeline and add a new keyframe with scale values set to 50% for the X and Y axis. Once you've done that move the playhead again to the last frame in the timeline and change the scale values back to 100%. Now play the animation and watch as the star shrinks and grows.
State Machines in Rive
We have now created two animations for our star shape. Next we'll get into State Machines in Rive. State Machines provide a way to visually connect your animations.The different animations you want to connect will be considered states. You can define conditions and then trigger transitions from one animation/state to another based on the given condition. This is really going to supercharge not only your animations but also the control you have over them inside your app. Let’s create our first State Machine and see what they are all about. Click on the “+” inside the Animations panel and select “State Machine”.
State Machines Overview

You should now see a State Machine inside the Animations panel. Double click on its name and rename it to “StarAnimation”. The names of your State Machines are important, because you will use those names to add them to your Flutter apps.
When you look inside the State Machine panel (located where the timeline used to be), you will see three states - Entry, Any State and Exit.

Entry
Transitions from the Entry state define which animation should play first.
Any State
Transitions from Any State will play the connected animation regardless of which state is currently active as long as the conditions on the transition are met.
Exit
Transitioning to the Exit state will exit the State Machine.
As you experiment with Rive and try creating your own animations, using these states and connecting your animations in the State Machine will become increasingly more intuitive.
Connecting Animations in a State Machine
Let’s create some simple transitions for our animations in the State Machine now.
First, click and drag the Scale and Rotation animations into the State Machine panel. Then drag and arrange the states in the following order - Entry > Rotation > Scale.
When you hover near an individual state state, you will see a small dot appear. Hover around the Entry state and when you see the dot click and drag towards the Rotation state. Then let go when you see the Rotation state is highlighted blue.
You now have a forward transition from the Entry to the Rotation state. Click on the play button inside the panel to see the transition in action. You can then hit the pause button to reset the State Machine.
Now add one more transition from Rotation to Scale. If you press play now you will only see the Scale animation. That is because for the transition from Rotation to Scale, the exit time is set to 0 milliseconds.
Click on the circle with the arrow inside of it between Rotation and Scale. Then enable the Exit Time setting to the right of the State Machine panel and set the time to 1000 milliseconds. This allows the Rotation animation to play in full before transitioning to the Scale one.
Inputs and Conditions
Look immediately to the left of the State Machine panel and find where it says “Inputs”. Now click on the “+” symbol to the right of where it says “Inputs” to add an input. You will see that you can choose a Number, a Boolean, or a Trigger.

Number Input
First let's add a number input and see how it works. Then, double click on the added input name and rename it to “Level”. Just like animations and State Machines, your input names should be thoughtfully created since they will be used inside your Flutter code.
We can now use this Level input to set conditions for our transitions. Select the transition from the Entry to the Rotation state. Then add a condition by clicking on the “+” symbol located next to the where it says “Conditions”, to the right of the State Machine panel. Then, select Level from the dropdown menu for the condition you just added and change the value from 0 to 2. Do the same thing for the transition from Rotation to Scale, but this time set the value to 4.
Now, set the animation to play and change the Level value in the Inputs panel to 2. When the value is changed to 2 you will see the Rotation animation play. Now change the value to 4 and you will see the Scale animation. Later in this tutorial we will learn how to change values for an input in your code to trigger different animation transitions.
Boolean Input
Now, let’s try creating a Boolean input. Add a Boolean and rename it to “Switch”. This input is exactly what it sounds like, a boolean which can only have 2 possible values - true or false. This input is represented by a checkbox in the Inputs panel.
Select the Entry to Rotation transition, delete the Level condition on it, and add a Switch condition with the value set to true. With this condition the Rotation animation will only play when the Switch input has a value of true. Go ahead press play and check the box next to the word Switch in the Inputs panel to see the animation.
You can use the Boolean input to create things like animated toggles in your app. Though, really the possibilities can extend well beyond these simple examples, as far as your imagination allows.
Trigger Input
The final input we are going to look at will be the Trigger input. Create a new Trigger and rename it to “Tap”. The Trigger at its core is a boolean, but the difference is that it automatically resets to false once it's set to true. So, it's kind of like a button. That's exactly the type of functionality we could use it for inside an app. In the Inputs panel, the Trigger is represented by a kind of radio button. When you click on it you can see the dot inside the circle, but then when you release your mouse button, it disappears. That is because the value automatically resets to false.
Let’s delete the Level condition we have on our Rotation to Scale transition and add the Tap as a new condition instead. Now, click play then check the Switch checkbox and then trigger the Tap input. You can now see that our animation transitions based on our defined conditions.
This concludes the Rive editor walkthrough. This by no means covers all of the features of this robust editor. However, you should now have enough knowledge to dissect the animations we pre-made for this tutorial as well as start creating your own basic animations.
Creating a Splash Screen Animation
We now know our way around the editor and how Rive animations are structured. Finally, we can start adding animations to our project.
Head over to splash_screen.dart and add a centered Container
with a width of 400 to the body
parameter of the Scaffold
. Make sure to import the Rive package in this file. As a child of the Container
, we'll add the riv file from our assets folder by providing the path to that file to the RiveAnimation.asset
constructor. We are going to use the radioSplashAnimation.riv file here. If you have your file stored online, you can also add it in using the RiveAnimation.network
constructor.
splash_screen.dart
Scaffold(
backgroundColor: Colors.yellow[600],
body: Center(
child: Container(
width: 400,
child: RiveAnimation.asset(
'assets/radioSplashAnimation.riv',
),
),
),
);
Now run the app and you should see an animation of a dancing radio with floating musical notes appear on the screen.
This is the absolute simplest way you can add an animation into your project. This animation doesn’t require any control over it, doesn’t have changing states, and just keeps playing in a loop.
Before we move on to the next set of animations, let’s make this splash screen a little more realistic. Since we don’t actually have much to load in this app, let’s just delay the navigation to the MusicPlayerPage
inside the initState
of the _SplashScrenState
. We want the animation to play for 3 seconds and then move onto the next page. This obviously is just for simulation purposes only.
splash_screen.dart
@override
void initState() {
super.initState();
Future.delayed(
Duration(seconds: 3),
() => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => MusicPlayerPage(),
),
),
);
}
Now let’s move on to implementing all of the animated elements for the MusicPlayerPage
.
One Shot Animations - Change Track Buttons

When we head over to the music_player_page.dart file we only have a single image of an album cover there. We want to add several animated elements to create a mock music player interface. In this section we are going to add the buttons for going to the previous and next track. These buttons will play the animation only once when they're pressed. This type of animation is also known as a one shot animation. So, let’s get started!
First, let’s add two controllers for our animations to the _MusicPlayerPageState
. We need two controllers, because we will have two change track buttons. To initialize the controllers correctly we need to add two late
variables of type RiveAnimationController
for each controller. We are marking them as late
, because we will be initializing them inside of initState
. Also, as you are doing this don't forget to import the Rive package into the file.
music_player_page.dart
class _MusicPlayerPageState extends State<MusicPlayerPage> {
late RiveAnimationController _prevButtonController;
late RiveAnimationController _nextButtonController;
@override
void initState() {
super.initState();
_prevButtonController = OneShotAnimation(
'onPrev',
autoplay: false,
);
_nextButtonController = OneShotAnimation(
'onNext',
autoplay: false,
);
}
...
For different types of animations, we need to use different types of controllers provided by the Rive package. Here we are using the OneShotAnimation
class to create the controller. Even though we are using the OneShotAnimation
class in the initialization, our variables are of type RiveAnimationController
. That is because the OneShotAnimation
class extends the SimpleAnimation
class, which extends the RiveAnimationController
class.
Even though we aren’t doing it here, you can define onStop
and onStart
functions for this controller. They are executed when the animation stops or starts respectively. The ‘onPrev’
and ‘onNext’
are the names of the animations which we defined in the Rive editor. So, when we assign this controller to the widget created using the RiveAnimation.asset
constructor, the controller will control the animation with the name you provide here. Lastly, we set the autoplay
parameter to false
, because we don’t want the animation to play when the page loads.
Now, head over to the Column
in the widget tree and add a SizedBox
and a Row
below the Container
. Then add two GestureDetector
widgets with RiveAnimation.asset
widgets as their children inside the Row
. We will provide the corresponding file paths here for our buttons along with the controllers we just created.
music_player_page.dart
SizedBox(
height: 60,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTapDown: (_) {},
child: SizedBox(
height: 115,
width: 115,
child: RiveAnimation.asset(
'assets/PrevTrackButton.riv',
controllers: [
_prevButtonController,
],
),
),
),
GestureDetector(
onTapDown: (_) {},
child: SizedBox(
height: 115,
width: 115,
child: RiveAnimation.asset(
'assets/NextTrackButton.riv',
controllers: [
_nextButtonController,
],
),
),
),
],
),
Next, we want to be able to control the animation when the GestureDetector
widget is tapped. Let’s create a separate function for this.
music_player_page.dart
void _playTrackChangeAnimation(RiveAnimationController controller) {
if (controller.isActive == false) {
controller.isActive = true;
}
}
When calling this function we need to pass a controller of type RiveAnimationController
to it. In this function we check to see if the animation is currently not active(playing) and then if it isn’t we set the isActive
property of the controller to true
.
Now go ahead and pass this function to the onTapDown
parameters of the two GestureDetector
widgets we created earlier. Make sure to pass the in the corresponding controller variables to the _playTrackChangeAnimation
function calls.
music_player_page.dart
...
GestureDetector(
onTapDown: (_) =>
_playTrackChangeAnimation(_prevButtonController),
child: SizedBox(
height: 115,
width: 115,
child: RiveAnimation.asset(
'assets/PrevTrackButton.riv',
controllers: [
_prevButtonController,
],
),
),
),
GestureDetector(
onTapDown: (_) =>
_playTrackChangeAnimation(_nextButtonController),
child: SizedBox(
height: 115,
width: 115,
child: RiveAnimation.asset(
'assets/NextTrackButton.riv',
controllers: [
_nextButtonController,
],
),
),
),
...
Go ahead, save your code, hot reload the app and try pressing on the buttons to see the animation. Next, we will be adding a more complicated animation element which relies on a State Machine.
State Machine Animation - Play/Pause Button
Understanding the Animation Configuration
When we learned about the Rive editor, we covered the essentials of State Machines. Now, we are going to add a State Machine animation into our app. If you look at the finished app video in the beginning of this tutorial, you can see that we have a play/pause button there. When the page loads, the button displays the play symbol. When the button is tapped, the play symbol rotates and fades out. Then the pause symbol fades in. When the button is tapped again after the previous transition completes, the pause symbol rotates and fades out. Then the play symbol fades back in. Every time we press the button, it goes back and forth between these two animations. This is because we set up our State Machine to do just that.

You can see here we have two animations - onPlay and onPause. We also have an isPlaying boolean input. Our animation starts off in the Entry state and when we set the isPlaying input to true, the onPlay animation runs. After that the animation will stay in the onPlay state. If we then set the isPlaying input to false, the transition to the onPause animation happens.
Let’s learn one new thing about State Machines. You may have already noticed that on the transition between onPause and onPlay there are two arrows. The back arrow pointing from the onPause to onPlay is what allows us to go back to the previous animation. So, if we made it to the onPause state in our animation lifecycle and from there we set the isPlaying back to true, it will play the onPlay animation. Then we can switch between the two animations/states. This is exactly the kind of effect we want in our app since we want to be able to tap the button to play and to pause.
Adding the State Machine Animation to the App
So, let’s finally add this animated play/pause button to our app. Adding a State Machine animation to the app takes quite a bit more code than the ones we implemented previously, so let’s do this step by step.
First, we need to get the riv file from our assets in form of ByteData
using rootBundle.load
. To use rootBundle
we need to import package:flutter/services.dart. The load method returns a Future
, so we'll use .then
to register a callback to get the ByteData
object. Then we will provide that data to RiveFile.import
constructor. After that we’ll store this data inside of a final
variable. We are going to do all of this inside of initState
.
music_player_page.dart
@override
void initState() {
super.initState();
...
rootBundle.load('assets/PlayPauseButton.riv').then(
(data) {
final file = RiveFile.import(data);
},
);
}
Now we need to find the main artboard inside the RiveFile
we just created and store that in another final
variable.
music_player_page.dart
rootBundle.load('assets/PlayPauseButton.riv').then(
(data) {
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
},
);
Next, we need to create a StateMachineController
from the artboard. Here we need the name we gave to our State Machine for this animation inside the Rive editor. To create this controller, we need to provide the artboard
variable and the name of our State Machine in a form of a String
to the StateMachineController.fromArtboard
constructor. We will then store this inside of a controller
variable.
music_player_page.dart
rootBundle.load('assets/PlayPauseButton.riv').then(
(data) {
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
var controller = StateMachineController.fromArtboard(
artboard,
'PlayPauseButton',
);
},
);
It's possible for the controller variable to equal null
, for example, in a case where you provide an incorrect State Machine name. So, before we proceed to the next step, we need to check if the controller
variable holding the StateMachineController
is null
. If it isn’t, we can proceed with the next steps.
music_player_page.dart
rootBundle.load('assets/PlayPauseButton.riv').then(
(data) {
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
var controller = StateMachineController.fromArtboard(
artboard,
'PlayPauseButton',
);
if (controller != null) {
}
},
);
For the next step we need to create two variables outside of initState
. One is going to be for the input we created in the Rive editor, which is of type bool
. The other is going to be for the play/pause button artboard.
music_player_page.dart
SMIInput<bool>? _playButtonInput;
Artboard? _playButtonArtboard;
Now, go back to the if statement we recently added. In here we need to provide the StateMachineController
we created earlier to the main artboard that we got from the rive file. Then we need to initialize our _playButtonInput
variable with the input we created in the State Machine for this animation inside the Rive editor.
music_player_page.dart
...
if (controller != null) {
artboard.addController(controller);
_playButtonInput = controller.findInput('isPlaying');
}
},
);
Our artboard
variable in this function is now loaded with the State Machine controller, so we can use setState
to initialize our _playButtonArtboard
variable with it below the if statement. Here's how the entire function should look when we're done with it.
music_player_page.dart
rootBundle.load('assets/PlayPauseButton.riv').then(
(data) {
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
var controller = StateMachineController.fromArtboard(
artboard,
'PlayPauseButton',
);
if (controller != null) {
artboard.addController(controller);
_playButtonInput = controller.findInput('isPlaying');
}
setState(() => _playButtonArtboard = artboard);
},
);
Before we add the animated element to our page, we need to account for a particular error. When the page initially loads, the build
method will run before the _playButtonArtboard
variable is initialized. That will produce a “Null check operator used on a null value”
error. To avoid this, add the following code between the SizedBox
and Row
widgets.
music_player_page.dart
...
SizedBox(
height: 60,
),
_playButtonArtboard == null
? SizedBox()
: Row(
...
Now, let's add another GestureDetector
widget between the next and previous track gesture detectors. This time the child of the GestureDetector
will be a Rive
widget. We don’t pass the file path to this widget, but instead pass in our _playButtonArtboard
variable to the artboard
parameter. We also need to add the bang operator after it to tell Dart that we're sure this variable won’t be null
. Since we just accounted for the scenario where it may be null
, we're safe to do this.
music_player_page.dart
GestureDetector(
onTapDown: (_) {},
child: SizedBox(
height: 125,
width: 125,
child: Rive(
artboard: _playButtonArtboard!,
fit: BoxFit.fitHeight,
),
),
),
Next we want to set up the logic for controlling this animation. Let’s create a separate function to do this.
music_player_page.dart
void _playPauseButtonAnimation() {
if (_playButtonInput?.value == false &&
_playButtonInput?.controller.isActive == false) {
_playButtonInput?.value = true;
} else if (_playButtonInput?.value == true &&
_playButtonInput?.controller.isActive == false) {
_playButtonInput?.value = false;
}
}
Since the execution of this animation depends on our input conditions, we are using the _playButtonInput
here. First, we are checking if the input value is false
and making sure the animation is not currently active. If this equates to true
then we will set the input value to true
. This will play the onPlay animation. We check to make sure the animation isn't currently active because we don’t want to be able to play the animation again if it is currently playing.
If the logic we just discussed equates to false
we'll do another check. If the input value is true
and the animation isn't currently active we will set the input value to false
. Setting the input to false will cause the onPause animation to play.
Now, add this function call to the onTapDown
parameter of the GestureDetector
widget for the play/pause button.
music_player_page.dart
...
GestureDetector(
onTapDown: (_) => _playPauseButtonAnimation(),
child: SizedBox(
height: 125,
width: 125,
child: Rive(
artboard: _playButtonArtboard!,
fit: BoxFit.fitHeight,
),
),
),
...
Go ahead, save and hot reload the app. Now when you tap the play/pause button you can see this animation in action, switching between onPause and onPlay states.
Simple Animation - Sound Wave
Since our app doesn’t actually play music, we will instead add a sound wave animation that can be paused and played based on the status of the play/pause button. This will be a looping animation. First, we are going to add a late
variable for the controller for this animation and then initialize it inside of initState
using the SimpleAnimation
class.
music_player_page.dart
class _MusicPlayerPageState extends State<MusicPlayerPage> {
...
late RiveAnimationController _soundWaveController;
...
@override
void initState() {
super.initState();
...
_soundWaveController = SimpleAnimation(
'loopingAnimation',
autoplay: false,
);
...
The name of our animation as defined in our Rive file is ‘loopingAnimation’
. On page load the player will be in a paused state, so we set autoplay
to false
here.
Now, head over to the end of our Column
widget and add a SizedBox
and a Container
below the Row
. We'll pass in RiveAnimation.asset
as the child of the Container
and essentially do the same thing we did for the track change buttons.
music_player_page.dart
...
SizedBox(
height: 40,
),
Container(
height: 100,
width: 400,
child: RiveAnimation.asset(
'assets/SoundWave.riv',
fit: BoxFit.contain,
controllers: [_soundWaveController],
),
),
],
Now, let’s add the logic for toggling this looping animation on and off. We are going to add a new function to do this.
music_player_page.dart
void _toggleWaveAnimation() => setState(
() => _soundWaveController.isActive = !_soundWaveController.isActive);
When this function runs it will use setState
and toggle the isActive
property of the _soundWaveController
. Since we want this animation to play and pause when the play/pause button is tapped, we will call this function from the existing _PlayPauseButtonAnimation
function.
music_player_page.dart
void _playPauseButtonAnimation() {
if (_playButtonInput?.value == false &&
_playButtonInput?.controller.isActive == false) {
_playButtonInput?.value = true;
_toggleWaveAnimation();
} else if (_playButtonInput?.value == true &&
_playButtonInput?.controller.isActive == false) {
_playButtonInput?.value = false;
_toggleWaveAnimation();
}
}
Now, when we tap the play button, it will play or pause the sound wave animation. Save your work and test the app. You should now see everything we implemented in this tutorial in working order.
Conclusion
Congratulations, you officially completed this tutorial! Hopefully this encourages you to start adding beautiful and functional animations into your apps. You should now have enough knowledge to do just that and enough confidence to advance your newly acquired skills.
Its like you read my mind! You appear to know a lot about this, like you wrote the book in it or something. I think that you could do with some pics to drive the message home a little bit, but instead of that, this is fantastic blog. An excellent read. I will certainly be back.
I do not even know how I ended up here, but I thought this post was great. I do not know who you are but certainly you’re going to a famous blogger if you are not already 😉 Cheers!
I simply could not go away your web site prior to suggesting that I really enjoyed the standard info a person supply on your guests? Is going to be back incessantly to investigate cross-check new posts.
Thank you, I have just been searching for information approximately this topic for a while and yours is the best I have found out so far. However, what in regards to the bottom line? Are you certain concerning the supply?
Wow, wonderful blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your site is great, as well as the content!
hi!,I like your writing so much! share we be in contact more approximately your article on AOL? I need a specialist in this area to resolve my problem. Maybe that is you! Looking ahead to see you.
you are in reality a just right webmaster. The site loading velocity is incredible. It seems that you are doing any unique trick. In addition, The contents are masterwork. you have performed a wonderful task on this topic!
Thank you for the auspicious writeup. It in fact was a amusement account it. Look advanced to far added agreeable from you! However, how can we communicate?
Attractive section of content. I just stumbled upon your blog and in accession capital to assert that I get actually enjoyed account your blog posts. Anyway I will be subscribing to your augment and even I achievement you access consistently fast.
What i don’t understood is in reality how you’re now not really a lot more smartly-favored than you might be now. You’re very intelligent. You understand therefore significantly in terms of this topic, produced me personally believe it from a lot of numerous angles. Its like women and men are not interested except it is one thing to accomplish with Woman gaga! Your own stuffs outstanding. Always care for it up!
What i don’t understood is in reality how you’re now not really a lot more smartly-favored than you might be now. You’re very intelligent. You understand therefore significantly in terms of this topic, produced me personally believe it from a lot of numerous angles. Its like women and men are not interested except it is one thing to accomplish with Woman gaga! Your own stuffs outstanding. Always care for it up!
I do not even know how I ended up here, but I thought this post was great. I don’t know who you are but definitely you’re going to a famous blogger if you aren’t already 😉 Cheers!
Nice blog here! Also your site loads up fast! What host are you using? Can I get your affiliate link to your host? I wish my web site loaded up as quickly as yours lol
Hi my loved one! I wish to say that this post is amazing, nice written and include approximately all vital infos. I’d like to peer more posts like this.
Wonderful web site. Lots of useful info here. I’m sending it to a few friends ans additionally sharing in delicious. And obviously, thanks to your effort!
My brother recommended I might like this web site. He was totally right. This post actually made my day. You cann’t imagine just how much time I had spent for this information! Thanks!
Wow, amazing blog layout! How long have you been blogging for? you made blogging look easy. The overall look of your web site is magnificent, as well as the content!
I do believe all the ideas you’ve presented for your post. They are really convincing and will certainly work. Nonetheless, the posts are too short for novices. May just you please lengthen them a little from subsequent time? Thanks for the post.
Thank you, I have just been searching for information approximately this topic for a while and yours is the best I have found out so far. However, what in regards to the bottom line? Are you certain concerning the supply?
I have been surfing online more than 3 hours today, yet I never found any interesting article like yours. It is pretty worth enough for me. In my opinion, if all web owners and bloggers made good content as you did, the web will be much more useful than ever before.
how to index backlink ? watch this
Earn passive income Affiliate Marketing Community
Increase your earnings Affiliate Discord
Increase your earnings Affiliate Marketing Community
Join affiliate marketing community Best Affiliate Community
Monetize your website Affiliate Discord
Learn about affiliate marketing Affiliate Discord
Hello i think that i saw you visited my weblog so i came to Return the favore Im trying to find things to improve my web siteI suppose its ok to use some of your ideas
There is definately a lot to find out about this subject. I like all the points you made
Fantastic site Lots of helpful information here I am sending it to some friends ans additionally sharing in delicious And of course thanks for your effort
I do not even understand how I ended up here, but I assumed this publish used to be great
you are in reality a good webmaster The website loading velocity is amazing It sort of feels that youre doing any distinctive trick Also The contents are masterwork you have done a fantastic job in this topic
My brother suggested I might like this website He was totally right This post actually made my day You cannt imagine just how much time I had spent for this information Thanks
Usually I do not read article on blogs however I would like to say that this writeup very compelled me to take a look at and do so Your writing taste has been amazed me Thanks quite nice post
you are in reality a just right webmaster The site loading velocity is incredible It seems that you are doing any unique trick In addition The contents are masterwork you have performed a wonderful task on this topic
I was recommended this website by my cousin I am not sure whether this post is written by him as nobody else know such detailed about my trouble You are amazing Thanks
Hi Neat post Theres an issue together with your web site in internet explorer may test this IE still is the marketplace chief and a good component of people will pass over your fantastic writing due to this problem
Live Coin Watch There is definately a lot to find out about this subject. I like all the points you made
BaddieHub very informative articles or reviews at this time.
Thank you for sharing this insightful article! I found the information really useful and thought-provoking. Your writing style is engaging, and it made the topic much easier to understand. Looking forward to reading more of your posts!
Nutra Gears Very well presented. Every quote was awesome and thanks for sharing the content. Keep sharing and keep motivating others.
Excellent blog here Also your website loads up very fast What web host are you using Can I get your affiliate link to your host I wish my web site loaded up as quickly as yours lol
Hi i think that i saw you visited my web site thus i came to Return the favore Im attempting to find things to enhance my siteI suppose its ok to use a few of your ideas
PB Pipes in Iraq At Elite Pipe Factory in Iraq, our PB pipes offer exceptional performance and durability, making them suitable for a variety of applications. Known for their resistance to high temperatures and chemicals, our PB pipes are crafted to meet the highest quality standards. As one of the best and most reliable pipe manufacturers in Iraq, Elite Pipe Factory is dedicated to providing products that excel in both performance and longevity. For more information on our PB pipes, visit elitepipeiraq.com.
For applications in corrosive environments, Elite Pipe Factory offers titanium pipes that provide unmatched strength and resistance. These pipes are ideal for industries requiring superior performance under harsh conditions. Our dedication to quality makes Elite Pipe Factory a leading choice in Iraq for titanium pipes. Discover more about our products at elitepipeiraq.com.
Concrete Pressure Pipes in Iraq Our concrete pressure pipes at Elite Pipe Factory are designed to withstand high pressure and are ideal for heavy-duty applications in water distribution and sewage systems. Engineered with precision, these pipes offer unmatched strength and reliability, making Elite Pipe Factory a top choice in Iraq for concrete pressure pipe solutions. Our commitment to excellence ensures that every product meets stringent quality standards. Learn more about our concrete pressure pipes by visiting elitepipeiraq.com.
Sky Scarlet I’m often to blogging and i really appreciate your content. The article has actually peaks my interest. I’m going to bookmark your web site and maintain checking for brand spanking new information.
dodb buzz This is really interesting, You’re a very skilled blogger. I’ve joined your feed and look forward to seeking more of your magnificent post. Also, I’ve shared your site in my social networks!
I simply could not go away your web site prior to suggesting that I really enjoyed the standard info a person supply on your guests Is going to be back incessantly to investigate crosscheck new posts
Nice blog here Also your site loads up fast What host are you using Can I get your affiliate link to your host I wish my web site loaded up as quickly as yours lol
Blue Techker I appreciate you sharing this blog post. Thanks Again. Cool.
Blue Techker This was beautiful Admin. Thank you for your reflections.
Blue Techker naturally like your web site however you need to take a look at the spelling on several of your posts. A number of them are rife with spelling problems and I find it very bothersome to tell the truth on the other hand I will surely come again again.
Jinx Manga There is definately a lot to find out about this subject. I like all the points you made
Tech Learner I do not even understand how I ended up here, but I assumed this publish used to be great
Strands Hint There is definately a lot to find out about this subject. I like all the points you made
Lois Sasson This is really interesting, You’re a very skilled blogger. I’ve joined your feed and look forward to seeking more of your magnificent post. Also, I’ve shared your site in my social networks!
Fantastic site Lots of helpful information here I am sending it to some friends ans additionally sharing in delicious And of course thanks for your effort
Blue Techker This was beautiful Admin. Thank you for your reflections.
Choose BWER for trusted weighbridge systems in Iraq, offering customized solutions to optimize your industrial operations and ensure precise weight measurement every time.
I don’t think the title of your article matches the content lol. Just kidding, mainly because I had some doubts after reading the article.
Noodlemagazine Great information shared.. really enjoyed reading this post thank you author for sharing this post .. appreciated
I do not even know how I ended up here but I thought this post was great I do not know who you are but certainly youre going to a famous blogger if you are not already Cheers
gab This is really interesting, You’re a very skilled blogger. I’ve joined your feed and look forward to seeking more of your magnificent post. Also, I’ve shared your site in my social networks!