Flutter Tutorial: Animated Icons | Creating an Animated Icon in Flutter
Learn how to use the AnimatedIcon widget in Flutter to create engaging animations for your app's icons. This tutorial covers how to set up the widget, define your animation controller, and configure your icon's animation parameters.
With these steps, you'll be able to create custom animated icons that respond to user interactions and add dynamic flair to your Flutter app.
- In this example we have stateful widget called ButtonAnimation and a stateful widget called SingleAnimatedIcon.
- The ButtonAnimation widget is a screen containing several SingleAnimatedIcon widgets. When a user taps on a SingleAnimatedIcon, the icon will animate in a different way.
- SingleAnimatedIcon is a widget that displays a single AnimatedIcon and has two boolean variables to determine the appearance of the icon. The variables are isBackground and isSlowMotion.
- The SingleAnimatedIcon widget is used several times in the ButtonAnimation widget, with different AnimatedIconData passed in as the animatedIconData variable. The animatedIconData variable is used to determine which icon to display in the AnimatedIcon.
Demo 1: Collection of animation icon
import 'package:flutter/material.dart';
import '../../data/my_colors.dart';
// This code defines a stateful widget that displays several variations of
// Flutter's AnimatedIcon class. The widget uses several helper classes and
// arrays to customize the appearance of each icon and animate them in slow
// motion if desired. The code also defines a reusable widget called
// SingleAnimatedIcon that simplifies the process of displaying a single
// AnimatedIcon.
class ButtonAnimation extends StatefulWidget {
const ButtonAnimation({super.key});
@override
ButtonAnimationState createState() => ButtonAnimationState();
}
class ButtonAnimationState extends State<ButtonAnimation> {
List<bool> isSelectedTab = List.generate(3, (index) => false);
List<bool> isSelectedIcon = List.generate(3, (index) => false);
List<bool> isSelectedText = List.generate(4, (index) => false);
List<bool> isSelectedAlign = List.generate(3, (index) => false);
List<bool> isSelectedTabIcon = List.generate(2, (index) => false);
@override
void initState() {
isSelectedTab[1] = true;
isSelectedIcon[1] = true;
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
// appBar: CommonAppBar.getPrimaryBackAppbarNew(context, "Animating Icons") as PreferredSizeWidget?,
body: SingleChildScrollView(
padding: const EdgeInsets.all(15),
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
//.................................................................
Container(
margin: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text("Animated Icon"),
Container(
margin: const EdgeInsets.only(top: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const <Widget>[
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.play_pause,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.add_event,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.arrow_menu,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.ellipsis_search,
),
],
),
),
Container(
margin: const EdgeInsets.only(top: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const <Widget>[
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.home_menu,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.view_list,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.menu_close,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.menu_arrow,
),
],
),
),
Container(
margin: const EdgeInsets.only(top: 24),
child:
const Text("Animated Icon with background"),
),
Container(
margin: const EdgeInsets.only(top: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const <Widget>[
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.play_pause,
isBackground: true,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.add_event,
isBackground: true,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.arrow_menu,
isBackground: true,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.ellipsis_search,
isBackground: true,
),
],
),
),
Container(
margin: const EdgeInsets.only(top: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const <Widget>[
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.home_menu,
isBackground: true,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.view_list,
isBackground: true,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.menu_close,
isBackground: true,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.menu_arrow,
isBackground: true,
),
],
),
),
Container(
margin: const EdgeInsets.only(top: 24),
child:
const Text("Slow Motion"),
),
Container(
margin: const EdgeInsets.only(top: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const <Widget>[
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.play_pause,
isBackground: true,
isSlowMotion: true,
),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.add_event,
isBackground: true,
isSlowMotion: true),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.arrow_menu,
isBackground: true,
isSlowMotion: true),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.ellipsis_search,
isBackground: true,
isSlowMotion: true),
],
),
),
Container(
margin: const EdgeInsets.only(top: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const <Widget>[
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.home_menu,
isBackground: true,
isSlowMotion: true),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.view_list,
isBackground: true,
isSlowMotion: true),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.menu_close,
isBackground: true,
isSlowMotion: true),
SingleAnimatedIcon(
animatedIconData: AnimatedIcons.menu_arrow,
isBackground: true,
isSlowMotion: true),
],
),
),
],
),
),
],
),
),
);
}
}
class SingleAnimatedIcon extends StatefulWidget {
// Widget to display a single AnimatedIcon
final AnimatedIconData animatedIconData;
// Data for the AnimatedIcon
final bool isBackground, isSlowMotion;
// Flags to determine the appearance of the icon (background and slow motion)
// Constructor
const SingleAnimatedIcon(
{Key? key,
required this.animatedIconData,
this.isBackground = false,
this.isSlowMotion = false})
: super(key: key);
@override
SingleAnimatedIconState createState() => SingleAnimatedIconState();
}
class SingleAnimatedIconState extends State<SingleAnimatedIcon>
with SingleTickerProviderStateMixin {
// State of the SingleAnimatedIcon widget
late ThemeData theme;
// Theme data for the widget
late AnimationController _animationController;
// Animation controller for the AnimatedIcon
bool isPlaying = false;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
// Setting the vsync to this makes the animation controller
// depend on this state
duration: Duration(milliseconds: widget.isSlowMotion ? 1500 : 400));
// The duration of the animation is set based on the isSlowMotion flag
}
@override
Widget build(BuildContext context) {
Color primaryColor = Theme.of(context).colorScheme.primary;
theme = Theme.of(context);
return ClipOval(
// Clipping the widget to an oval shape
child: Material(
color: widget.isBackground
? MyColors.primary.withAlpha(20)
: Colors.transparent, // button color
child: InkWell(
splashColor: primaryColor,
// inkwell color
child: SizedBox(
width: 44,
height: 44,
child: IconButton(
iconSize: 24,
icon: AnimatedIcon(
icon: widget.animatedIconData,
progress: _animationController,
color: primaryColor,
),
// Animated icon with the animation controller's progress
onPressed: () {
if (isPlaying) {
_animationController.reverse();
setState(() {
isPlaying = false;
});
} else {
_animationController.forward();
setState(() {
isPlaying = true;
});
}
},
// Toggling the animation playback on button press
)),
onTap: () {},
),
),
);
}
}
..
class MyColors {
static const Color primary = Color(0xFF12376F);
}
..
Demo 2: Flutter Animated Icon Example
This Flutter example demonstrates how to create an animated icon using the AnimatedIcon widget. The icon used in this example is the AnimatedIcons.menu_arrow, which animates between the menu and arrow icons. The animation is looped back and forth continuously using an AnimationController and the repeat method. The example also shows how to specify the size and semantic label for the animated icon.
import 'package:flutter/material.dart';
void main() {
runApp(const AnimatedIconApp());
}
class AnimatedIconApp extends StatelessWidget {
const AnimatedIconApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
// set theme data for the app
theme: ThemeData(
colorSchemeSeed: const Color(0xff6750a4),
useMaterial3: true,
),
home: const Scaffold(
// set the body of the scaffold to the AnimatedIconExample widget
body: AnimatedIconExample(),
),
);
}
}
class AnimatedIconExample extends StatefulWidget {
const AnimatedIconExample({super.key});
@override
State<AnimatedIconExample> createState() => _AnimatedIconExampleState();
}
class _AnimatedIconExampleState extends State<AnimatedIconExample>
with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation<double> animation;
@override
void initState() {
super.initState();
// create an animation controller with a duration of 2 seconds
controller = AnimationController(
vsync: this, // the ticker provider
duration: const Duration(seconds: 2),
)
..forward() // start the animation by moving it forward
..repeat(reverse: true); // loop the animation forward and backward
// create a tween to interpolate between 0.0 and 1.0 over the animation duration
animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller);
}
@override
void dispose() {
// dispose of the animation controller when the widget is removed from the tree
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimatedIcon(
// set the icon to be an animated menu arrow
icon: AnimatedIcons.menu_arrow,
// set the animation progress to be the animation created in initState
progress: animation,
// set the size of the icon
size: 72.0,
// set the semantic label of the icon
semanticLabel: 'Show menu',
),
),
);
}
}
..
Ref code: https://api.flutter.dev/flutter/material/AnimatedIcon-class.html
Comments
Post a Comment