Kasper
Kasper

Reputation: 13622

Animate a color periodically in flutter

I have a container widget that I try to animate from Colors.blue to Colors.blueGrey and back periodically every 2 seconds.

How can I most easily tackle this in Flutter?

Upvotes: 9

Views: 8460

Answers (3)

Richard Sipher
Richard Sipher

Reputation: 131

to expand @Karol Lisiewicz answer, if you use colors with opacity it's better to user bool flipper variable, because sometimes colors may not animated in error of equality. code with bool flipper variable:

import 'dart:async';

import 'package:flutter/material.dart';

class AnimationTest extends StatefulWidget {
  const AnimationTest({super.key});

  @override
  State<AnimationTest> createState() => _AnimationTestState();
}

class _AnimationTestState extends State<AnimationTest> {
  final _animationDuration = const Duration(seconds: 2);
  late Timer _timer;
  bool _shouldFlipColor = true;
  Color _color = Colors.blue.withOpacity(0.4);

  @override
  void initState() {
    super.initState();
    _timer = Timer.periodic(_animationDuration, (timer) => _changeColor());
  }

  @override
  void dispose() {
    super.dispose();
    _timer.cancel();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      width: 100,
      height: 100,
      duration: _animationDuration,
      color: _color,
    );
  }

  void _changeColor() {
    _shouldFlipColor = !_shouldFlipColor;
    setState(() {
      _color = _shouldFlipColor ? Colors.blue : Colors.blue.withOpacity(0.4);
    });
  }
}

Upvotes: 0

Karol Lisiewicz
Karol Lisiewicz

Reputation: 674

I would suggest using the AnimatedContainer. This widget allows you to build it with a particular atribute like color and when you rebuild it with a different value it performs linear interpolation between those values.

@override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      width: 100,
      height: 100,
      duration: _animationDuration,
      color: _color,
    );
  }

Then you just have to rebuild the widget with a different color:

void _changeColor() {
    final newColor = _color == Colors.blue ? Colors.blueGrey : Colors.blue;
    setState(() {
      _color = newColor;
    });
  }

The make it periodically I would use a timer class:

_timer = Timer.periodic(_animationDuration, (timer) => _changeColor());

The whole code:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class AnimationTest extends StatefulWidget {
  @override
  _AnimationTestState createState() => _AnimationTestState();
}

class _AnimationTestState extends State<AnimationTest> {
  final _animationDuration = Duration(seconds: 2);
  Timer _timer;
  Color _color;

  @override
  void initState() {
    super.initState();
    _timer = Timer.periodic(_animationDuration, (timer) => _changeColor());
    _color = Colors.blue;
  }

  void _changeColor() {
    final newColor = _color == Colors.blue ? Colors.blueGrey : Colors.blue;
    setState(() {
      _color = newColor;
    });
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      width: 100,
      height: 100,
      duration: _animationDuration,
      color: _color,
    );
  }

  @override
  void dispose() {
    super.dispose();
    _timer.cancel();
  }
}

Upvotes: 9

Tinus Jackson
Tinus Jackson

Reputation: 3663

You can use an infinite while loop, don't think this is the best way of doing this, but it gets the job done.

I have a Color Changing class

class ColorChanger extends StatefulWidget {


@override
  _ColorChangerState createState() => _ColorChangerState();
}

class _ColorChangerState extends State<ColorChanger>
    with SingleTickerProviderStateMixin {
  AnimationController _animationController;
  Animation _colorTween;

  @override
  void initState() {
    _animationController = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1999));
    _colorTween = ColorTween(begin: Colors.blue, end: Colors.blueGrey)
        .animate(_animationController);
    changeColors();
    super.initState();
  }

  Future changeColors() async {
    while (true) {
      await new Future.delayed(const Duration(seconds: 2), () {
        if (_animationController.status == AnimationStatus.completed) {
          _animationController.reverse();
        } else {
          _animationController.forward();
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _colorTween,
      builder: (context, child) => Container(
            color: _colorTween.value,
          ),
    );
  }
}

This is a rough example, but should lead you in the right direction.

Please see ColorTween Class

Upvotes: 10

Related Questions