'Flutter - Blinking button
I need a call the user attention to a button. The first idea that came to mind is to add a blink animation. I really don't know how to do that, but I tried to make it work with the following code:
Timer timer = new Timer(new Duration(seconds: 1), () {
//basic logic to change the color variable here
setState(() {});
});
It is straightforward, every second setState is called and the widget is created again.
But it doesn't work, the timer is called only once. And, besides that, calling setState within a Timer seems wrong to me.
There is a better approach to this?
Solution 1:[1]
You can do that with this approach also. My logic is a little different I am using alternate for animation. Once animation completed in forward I'm coming backward.
Which is good for eyesight
ie:
forward -> backward
backward -> forward
and so on
import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Wordpress App',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new BlinkAnimation(),
);
}
}
class BlinkAnimation extends StatefulWidget {
@override
_BlinkAnimationState createState() => _BlinkAnimationState();
}
class _BlinkAnimationState extends State<BlinkAnimation>
with SingleTickerProviderStateMixin {
Animation<Color> animation;
AnimationController controller;
initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
final CurvedAnimation curve =
CurvedAnimation(parent: controller, curve: Curves.linear);
animation =
ColorTween(begin: Colors.white, end: Colors.blue).animate(curve);
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
controller.forward();
}
setState(() {});
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: new Text('Blink Animation'),
),
body: new Center(
child: AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
return new Container(
child: new RaisedButton(
color: animation.value,
onPressed: () {
controller.forward();
},
child: Text('Blink Animation'),
),
);
},
),
),
);
}
dispose() {
controller.dispose();
super.dispose();
}
}
Solution 2:[2]
Here is the example from the answer by @nitishk72 but with code updated to null safety and more recent Flutter version.
Result:
Code:
You can just copy this to DartPad.dev and it will work :)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Blink animation demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: BlinkAnimation(),
);
}
}
class BlinkAnimation extends StatefulWidget {
@override
_BlinkAnimationState createState() => _BlinkAnimationState();
}
class _BlinkAnimationState extends State<BlinkAnimation>
with SingleTickerProviderStateMixin {
late Animation<Color?> animation;
late AnimationController controller;
@override
initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
final CurvedAnimation curve =
CurvedAnimation(parent: controller, curve: Curves.linear);
animation =
ColorTween(begin: Colors.white, end: Colors.blue).animate(curve);
// Keep the animation going forever once it is started
animation.addStatusListener((status) {
// Reverse the animation after it has been completed
if (status == AnimationStatus.completed) {
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
controller.forward();
}
setState(() {});
});
// Remove this line if you want to start the animation later
controller.forward();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Blink Animation'),
),
body: Center(
child: AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) {
return Container(
color: animation.value,
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () {
// Start the animation or do something else on click
// controller.forward();
print('button does something!');
},
child: const Text('Blink Animation'),
),
);
},
),
),
);
}
@override
dispose() {
controller.dispose();
super.dispose();
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | nitishk72 |
| Solution 2 | Aleksandar |

