Dead Simple Example of Using Keys in Flutter Widgets

Search for a command to run...

No comments yet. Be the first to comment.
This is the series related to my experience building game with Flutter and Dart. It is basically a diary. At first I implement feature and then add a post about it. https://locadederta.com/sloboda
Захотілося розбавити статті про Flutter&Dart чимось прикладним, а не черговим описом Todo/Counter/REST/CRUD фігнею. Під час розробки покрокової гри в стилі "побудуй селище" у мене постала необхідність у впроваджені сутності подій. За задумом, в зале...
Build. Craft. Explore.

Заселяємо південь України!

Hey! We just published the second content update for our game Sloboda 2. This update is free for anyone who already purchased our game. If you want to purchase it, then pick your platforms: Apple App Store: https://apps.apple.com/us/app/loca-deserta-...

Привіт, компана! Ось і настав час Січневого оновлення для нашої гри Слобода 2! Це оновлення безкоштовне для всіх, хто придбав гру. Якщо ж ще не придбали, то можете це зробити по цих посиланнях: Apple App Store: https://apps.apple.com/ua/app/loca-dese...

Статистика запуску гри Трохи більше двох тижнів тому ми випустили гру на всіх магазинах. І одразу ж попали в Топ платних ігор 🇺🇦українського App Store! Купити можна на iOS по посиланню: https://apps.apple.com/ua/app/loca-deserta-sloboda-2/id164250...

Lots of folks struggle to understand when to use keys in Flutter. In this very short article I will show you nice example where they must be used.
There is an all-in-one video When to Use Keys - Flutter Widgets 101 Ep. 4 that tells you everything you need.
The examples are great but I would like to show you another application of Flutter keys when you need animations!
Jump directly to DartPad example
In my game Chumaki I wanted to animate the NPC level up by showing a growing widget with a text "New Level", like this:

I implemented the following widget, it runs initial animation when the widget is created and scales the widget from 0 to 1 (full size).
class ScaleAnimated extends StatefulWidget {
final Widget child;
final Duration duration;
const ScaleAnimated({Key? key, required this.child, required this.duration})
: super(key: key);
@override
_ScaleAnimatedState createState() => _ScaleAnimatedState();
}
class _ScaleAnimatedState extends State<ScaleAnimated>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
upperBound: 1.0,
lowerBound: 0.0);
_controller.forward();
_animation = CurvedAnimation(parent: _controller, curve: Curves.linear);
}
@override
Widget build(BuildContext context) {
return ScaleTransition(
scale: _animation,
child: widget.child,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
The widget is called in this way:
ScaleAnimated(
duration: const Duration(seconds: 2),
child: Text("New Level: $level"),
),
But the animation was playing only once...I level up one time, second time, third...The widget updated the level value but the animation was not playing! I checked debugger - the build method was called each time I level upped but initState was never called again.
Please watch the video When to Use Keys - Flutter Widgets 101 Ep. 4.
TLDR: Flutter builds new tree on player level up event. The new widget is of the same type as previous, their keys are null, so Flutter thinks it is the same widget and just updates it with new state (text input parameter). The initState is not called cause old widget was reused.
We have to help Flutter to distinguish identical widgets like in our case. The good thing: we dont have to change the Widget source code. We need to provide a Key parameter for its constructor like this:
ScaleAnimated(
key: ValueKey(counter), // <--- here we provide key!
duration: const Duration(seconds: 2),
child: Text(
"New Level: $counter"),
),
We have a nice way of knowing when we really have to animate "New Level" widget - when the new level is received. This unique value can be used as a ValueKey.
Please open this link for a very short example of using ScaleAnimation with and without keys: