skip to Main Content

So I am trying to achieve something similar to this Flutter example provided on the documentation

But I do not want it to be subject to a button, I want it to execute the animation by itself, and do it non-stop.

At least I need a Tween for the height, width and color, however, I am finding myself in a confusing situation on how to animate all of them, I kinda did it, but I know I’m missing a Animation property on my Widget, this is my result so far:

Screen recording gif

It is making jumps between the random values that are being generated.

This is my code:

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

  @override
  State<AnimatedSquare> createState() => _AnimatedSquareState();
}

class _AnimatedSquareState extends State<AnimatedSquare>
  with SingleTickerProviderStateMixin{

  late final AnimationController controller;
  late Tween<double> containerWidth;
  late Tween<double> containerHeight;
  late Tween<Color> containerColor;
  Random random = Random();

  @override
  void initState() {
    controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 800)
    )
    ..forward()
    ..addListener(() {
      if(controller.isCompleted) {
        setNewValues();
        controller.forward();
      }
    });
    containerWidth = Tween<double>(
      begin: 250,
      end: random.nextInt(300).toDouble()
    );
    containerHeight = Tween<double>(
      begin: 250,
      end: random.nextInt(300).toDouble()
    );
    containerColor = Tween(
      begin: Colors.red,
      end: Color.fromRGBO(
        random.nextInt(255),
        random.nextInt(255),
        random.nextInt(255), 
        1
      )
    );

    super.initState();
  }

  void setNewValues() {
    containerWidth.begin = containerWidth.end;
    containerHeight.begin = containerHeight.end;
    containerColor.begin = containerColor.end;
    controller.reset();
    containerWidth.end = random.nextInt(300).toDouble();
    containerHeight.end = random.nextInt(300).toDouble();
    containerColor.end = Color.fromRGBO(
      random.nextInt(255),
      random.nextInt(255),
      random.nextInt(255),
      1
    );
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: (context, child) {
        return Container(
          height: containerHeight.begin,
          width: containerWidth.begin,
          decoration: BoxDecoration(
            color: containerColor.begin
          ),
        );
      },
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

Can anyone help me getting this issue resolved?, I couldn’t find much info on the internet, used this question as my last resource

3

Answers


  1. Chosen as BEST ANSWER

    So basically I used part of @diegoveloper answer in order to solve my issue, I just added a Animation variable for each Tween, since I needed to get the end and begin properties into the setNewValues() method.

    The final code:

    class AnimatedSquare extends StatefulWidget {
      const AnimatedSquare({super.key});
    
      @override
      State<AnimatedSquare> createState() => _AnimatedSquareState();
    }
    
    class _AnimatedSquareState extends State<AnimatedSquare>
        with SingleTickerProviderStateMixin {
    
      late final AnimationController controller;
      late Tween<double> containerWidth;
      late Tween<double> containerHeight;
      late Tween<Color?> containerColor;
      late Animation<double> animContainerWidth;
      late Animation<double> animContainerHeight;
      late Animation<Color?> animContainerColor;
      Random random = Random();
    
      @override
      void initState() {
        controller = AnimationController(
          vsync: this,
          duration: const Duration(milliseconds: 800)
        )..addStatusListener((status) {
          if (status == AnimationStatus.completed) {
            setNewValues();
            controller.forward(from: 0);
          }
        })..forward();
    
        containerWidth = Tween<double>(
          begin: 250,
          end: random.nextInt(300).toDouble()
        );
    
        containerHeight = Tween<double>(
          begin: 250,
          end: random.nextInt(300).toDouble()
        );
    
        containerColor = ColorTween(
          begin: Colors.red,
          end: Color.fromRGBO(
            random.nextInt(255),
            random.nextInt(255),
            random.nextInt(255),
            1
          )
        );
    
        animContainerWidth = containerWidth.animate(CurvedAnimation(
          parent: controller,
          curve: Curves.fastOutSlowIn
        ));
        animContainerHeight = containerHeight.animate(CurvedAnimation(
          parent: controller,
          curve: Curves.fastOutSlowIn
        ));
        animContainerColor = containerColor.animate(CurvedAnimation(
          parent: controller,
          curve: Curves.fastOutSlowIn
        ));
    
        super.initState();
      }
    
      void setNewValues() {
        containerWidth.begin = containerWidth.end;
        containerHeight.begin = containerHeight.end;
        containerColor.begin = containerColor.end;
        controller.reset();
        containerWidth.end = random.nextInt(300).toDouble();
        containerHeight.end = random.nextInt(300).toDouble();
        containerColor.end = Color.fromRGBO(
          random.nextInt(255),
          random.nextInt(255),
          random.nextInt(255),
          1
        );
    
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: AnimatedBuilder(
            animation: controller,
            builder: (context, child) {
              return Container(
                height: animContainerHeight.value,
                width: animContainerWidth.value,
                decoration: BoxDecoration(
                  color: animContainerColor.value,
                  borderRadius: BorderRadius.circular(30)
                ),
              );
            },
          ),
        );
      }
    
      @override
      void dispose() {
        controller.dispose();
        super.dispose();
      }
    }
    
    • The result:

    Screen recording

    Thanks a lot!


  2. AnimatedContainer(
          height: containerHeight.begin,
          width: containerWidth.begin,
          decoration: BoxDecoration(color: containerColor.begin),
          duration: const Duration(seconds: 2),
          curve: Curves.fastOutSlowIn,
        );
    

    use this as a return at AnimatedBuilder

    Login or Signup to reply.
  3. You just need to use Animation with a Tween for a specific movement/action.

    Also you need to listen the addStatusListener instead the animation listener.

    This is your code fixed.

    class _AnimatedSquareState extends State<AnimatedSquare>
        with SingleTickerProviderStateMixin {
      late final AnimationController controller;
      late Animation<double> containerWidth;
      late Animation<double> containerHeight;
      late Animation<Color?> containerColor;
      Random random = Random();
    
      @override
      void initState() {
        controller = AnimationController(
            vsync: this, duration: const Duration(milliseconds: 800))
          ..addStatusListener((status) {
            if (status == AnimationStatus.completed) {
              setNewValues();
              controller.forward(from: 0);
            }
          })
          ..forward();
        setNewValues();
    
        super.initState();
      }
    
      void setNewValues() {
        containerWidth =
            Tween<double>(begin: 250, end: random.nextInt(300).toDouble()).animate(
          controller,
        );
        containerHeight =
            Tween<double>(begin: 250, end: random.nextInt(300).toDouble()).animate(
          controller,
        );
        containerColor = ColorTween(
                begin: Colors.red,
                end: Color.fromRGBO(random.nextInt(255), random.nextInt(255),
                    random.nextInt(255), 1))
            .animate(
          controller,
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: AnimatedBuilder(
            animation: controller,
            builder: (context, child) {
              return Container(
                height: containerHeight.value,
                width: containerWidth.value,
                decoration: BoxDecoration(color: containerColor.value),
              );
            },
          ),
        );
      }
    
      @override
      void dispose() {
        controller.dispose();
        super.dispose();
      }
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search