'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:

Flutter blinking text code example

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