Today we'll be learning how Flutter provides its users with a thrilling experience in being able to apply concepts of physics to their animations. Before we dive right in, let's have a brief recap of what Flutter offers.
Flutter is a UI development toolkit primarily used for building applications for various platforms using a single codebase. It is completely open-source and is a product of Google.
Simply put, this means that developers can write the code once and use it on different platforms without having to start from scratch for each one.
Note: We offer various courses if you aim to continue your journey in learning Flutter!
Flutter needs a programming language to build and run applications. Dart is used as the primary language for developing applications with the Flutter framework. We will be using Dart in our code as well.
Note: Before proceeding with the answer, ensure that your Flutter setup is complete.
A physics simulation is a computer-based model that replicates the behavior of physical systems in a virtual environment. It basically tries to copy how real-world things move and interact with each other based on the rules of physics. Therefore, this helps us see how objects would behave in different situations without having to do actual physical experiments.
Flutter offers a physics library that contains different simulations that work differently based on physics concepts. For instance, gravity simulation works by implementing a gravity environment to aid falls, while a spring simulation focuses on the stiffness of the spring or the mass of the object.
If you aim to get ahold of the basics first, feel free to check out our answer on basic physics simulations in Flutter.
In this Flutter code, we will create an exciting physics animation with bouncing balls. Our animation demonstrates the behavior of five balls, each with its own set of physics properties, bouncing in response to the physics simulation.
initState
methodIn the initState
method, we initialize the animation controllers and the corresponding stiffness
, damping
, and color
for each ball. We use the addListener
method of the animation controllers to build our UI again whenever the animation value changes. We then use controller.animateWith
to trigger the physics-based animation for each ball. The animation will cause the balls to move based on our defined properties, resulting in a bouncing motion.
@overridevoid initState() {super.initState();ball1Data = BallData(stiffness: 100, damping: 1, color: Colors.blue);ball2Data = BallData(stiffness: 200, damping: 1.2, color: Colors.red);ball3Data = BallData(stiffness: 300, damping: 1.4, color: Colors.green);ball4Data = BallData(stiffness: 400, damping: 1.6, color: Colors.yellow);ball5Data = BallData(stiffness: 500, damping: 1.8, color: Colors.orange);for (var ballData in [ball1Data, ball2Data, ball3Data, ball4Data, ball5Data]) {ballData.controller = AnimationController(vsync: this, upperBound: 500)..addListener(() {setState(() {});});ballData.controller.animateWith(ballData.simulation);}}
The user interface consists of a Column
widget that includes an app bar and the main body. We divide our body into two sections. The first one contains a Text
widget titled "Bouncing Balls," displayed in a white and bolded font using properties like fontWeight
, color
, and fontSize
. The second section is a Container
with a dark background color, simulating the floor where the balls bounce. Inside this container, we have a Stack
widget to help position the balls.
@overrideWidget build(BuildContext context) {return MaterialApp(home: Scaffold(backgroundColor: Colors.black,appBar: AppBar(title: Text('Cool Physics Animation',style: TextStyle(fontSize: 24),),centerTitle: true,backgroundColor: Colors.blueGrey[900],elevation: 0,),body: Column(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [Padding(padding: const EdgeInsets.symmetric(vertical: 20.0),child: Text('Bouncing Balls',style: TextStyle(fontSize: 32,color: Colors.white,fontWeight: FontWeight.bold,),),),Container(width: double.infinity,height: 300,color: Colors.blueGrey[900],child: Stack(children: [Positioned(left: 50,top: ball1Data.controller.value,child: BallWidget(color: ball1Data.color),),Positioned(left: 120,top: ball2Data.controller.value * 1.5,child: BallWidget(color: ball2Data.color),),Positioned(left: 190,top: ball3Data.controller.value * 0.8,child: BallWidget(color: ball3Data.color),),Positioned(left: 260,top: ball4Data.controller.value * 1.2,child: BallWidget(color: ball4Data.color),),Positioned(left: 330,top: ball5Data.controller.value * 0.5,child: BallWidget(color: ball5Data.color),),],),),],),),);}
BallWidget
custom widgetWe create a custom widget called BallWidget
to represent the balls. The widget takes the color
argument determining the ball's appearance. It's displayed as a circular container with our given color.
class BallWidget extends StatelessWidget {final Color color;BallWidget({this.color});@overrideWidget build(BuildContext context) {return Container(width: 50,height: 50,decoration: BoxDecoration(shape: BoxShape.circle,color: color,),);}}
Note: Stateless widgets remain the same throughout while stateful widgets are subject to change due to interactivity.
AnimationController
The animation controllers and spring simulations work together to create the physics-based bouncing animation for each ball. The AnimationController
updates the animation values, and the setState
method rebuilds UI to show the moving balls.
Basically, the physics simulation is based on the spring equation, which in turn moves the balls.
0.0 is the starting
300.0 is the ending
10 is the velocity
class BallData {AnimationController controller;final SpringSimulation simulation;final double stiffness;final double damping;final Color color;BallData({this.stiffness, this.damping, this.color}): simulation = SpringSimulation(SpringDescription(mass: 1,stiffness: stiffness,damping: damping,),0.0,300.0,10,);}
Note: You can change the settings of the physics simulation to see how the effect on the shapes changes.
Hurray! Our explanation is now complete, and we're ready to put together our code. The given code is completely executable, and you can experiment with it to see how these simulations work.
const express = require('express'); const cors = require('cors'); const path = require('path'); const app = express(); const port = 8080; // Enable CORS for all routes app.use(cors()); // Serve the Flutter web application app.use(express.static(path.join(__dirname, 'build/web'))); // Start the server app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); });
This is how our application starts initially.
Our animation is ready! Let's see how the balls move due to the spring simulation.
Similar to the previous concept, we can make use of the GravitySimulation
module to create a Flutter application with the force of gravity. The values can be changed according to our needs.
Here's how it works.
const express = require('express'); const cors = require('cors'); const path = require('path'); const app = express(); const port = 8080; // Enable CORS for all routes app.use(cors()); // Serve the Flutter web application app.use(express.static(path.join(__dirname, 'build/web'))); // Start the server app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); });
We implement a gravity simulation to create a falling animation for multiple squares. The GravitySimulation
class is used to model this.
We initialize three AnimationController
instances to drive the animations and three GravitySimulation
instances with different acceleration values for our squares.
The square positions are updated using the controller.value
and the GravitySimulation.x(controller.value)
methods within a Positioned
widget. This causes the squares to fall with gravity-based animations on the screen.
This is how our application starts initially.
Our animation is ready! Let's see how different gravity values work on each square.
Physics simulations in computer science can have amazing advantages, including but not limited to the list mentioned below.
Use cases |
Realistic object movement in games and simulations |
Natural-looking cloth and hair animations in animations and movies |
Accurate physics-based collisions for game development |
Dynamic fluid and particle effects in visual effects and simulations |
Understanding complex physical phenomena in scientific research |
Precise engineering simulations for structural analysis |
Note: Explore the Flutter series here!
Test your knowledge on Flutter’s physics simulation!
How does the SpringSimulation
differ from the GravitySimulation
?
Free Resources