Adding Magic with Flutter Animations 🧙♂️✨
Animations can transform a static app into an engaging experience—and with Flutter, adding those magical touches is easier than you think! In this tutorial, I’ll show you how to create a simple sliding animation for a login screen, perfect for impressing users and adding a touch of polish to your app.
Here's a quick look at what we'll be building:
Why Add Animations?
Users love smooth transitions. Animations make apps feel alive, guide attention, and create a memorable experience. Flutter’s animation framework is powerful yet intuitive, letting you build complex effects with minimal code.
Set Up Your Flutter Project
Create a new Flutter project in Android Studio/VS Code.
flutter create flutter_login_animation
Code the Sliding Animation
Step 1: Setting Up the Foundation
First, we need a StatefulWidget. Animations require a state that can change over time, and a StatefulWidget is perfect for this. We'll also mix in SingleTickerProviderStateMixin, which is essential for our AnimationController to function correctly.
import 'package:flutter/material.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen>
with SingleTickerProviderStateMixin {
// Animation variables will go here
@override
Widget build(BuildContext context) {
// Our UI will be built here
}
}
Step 2: Initializing the Animations
Inside our _LoginScreenState, we'll declare our animation controllers and define the animations themselves. We'll use an AnimationController to manage the animation's lifecycle.
We will create two animations:
We'll set these up in the initState() method, which is called once when the widget is first created.
late AnimationController _controller;
late Animation<Offset> _slideAnimation;
late Animation<double> _fadeAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 800),
);
// 1. Slide Animation
_slideAnimation = Tween<Offset>(
begin: Offset(0, 1), // Start off-screen (bottom)
end: Offset.zero, // End at its natural position
).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));
// 2. Fade Animation
_fadeAnimation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.5, 1.0), // Fade in during the second half of the animation
),
);
// Start the animation
_controller.forward();
}
Key Concepts:
And don't forget to dispose of the controller when the widget is removed to prevent memory leaks!
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Step 3: Building the UI
Now, let's build the visual components. We'll use a Stack to layer a gradient background behind our animated elements.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
// The beautiful gradient background
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue.shade700, Colors.blue.shade300],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Our animated logo will go here
// Our animated login form will go here
],
),
),
],
),
);
}
Step 4: Applying the Animations
This is where the magic happens. We'll use the FadeTransition and SlideTransition widgets to apply our animations to the UI elements.
// Inside the Center's child Column
...
FadeTransition(
opacity: _fadeAnimation,
child: Image(
image: AssetImage('assets/logo.png'), // Make sure you have a logo in your assets
width: 240,
height: 240,
color: Colors.white,
),
),
SlideTransition(
position: _slideAnimation,
child: _buildLoginCard(), // We will create this helper method next
),
...
Step 5: Creating the Login Card
To keep our build method clean, we'll extract the login form into its own method, _buildLoginCard(). This method returns a styled Container with text fields and a button.
Widget _buildLoginCard() {
return Container(
margin: EdgeInsets.all(20),
padding: EdgeInsets.all(25),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 10,
offset: Offset(0, 5),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Welcome Back!",
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
),
SizedBox(height: 25),
TextField(
decoration: InputDecoration(
labelText: "Email",
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(),
),
),
SizedBox(height: 15),
TextField(
obscureText: true,
decoration: InputDecoration(
labelText: "Password",
prefixIcon: Icon(Icons.lock),
border: OutlineInputBorder(),
),
),
SizedBox(height: 25),
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 15, horizontal: 40),
),
child: Text("Sign In"),
),
],
),
);
}
Conclusion
And that's it! With just a few animation widgets and a controller, we've transformed a static login screen into a dynamic and professional-looking entry point for your application. These small details in the user experience are what set great apps apart.
The full code is provided above. Feel free to experiment with different Curves, Durations, and Tween values to create your own unique animations.
What are your favorite ways to add a little flair to your Flutter apps? Share your thoughts in the comments below!
#Flutter #Dart #MobileDevelopment #UIUX #Animation #FlutterDev #AppDevelopment