4

What i want is to chain multiple Animation object like if we have an Animation<double> that goes from 0 to 40 (let's call it the big one) and i have another 4 Animation<double> object what i want is

  1. when the big animation starts the first animation start with it , but it end's when the big one reach 10.
  2. when the big one reach 10 the second animation start's and end's when the big one reach 20. etc...

any one knows how to do it in flutter ??

2

1 Answer 1

8

It sounds like staggered animations. Basically, you can create an animation controller and set the total duration time. Then, you can create a separate tween for each animation you want to perform. For each tween, you can define a curve, for that curve you can define an interval in the percentage of the total duration of the animation. There is a pretty good example in a flutter.dev when you search for staggered animations. Note: they don't have to be one after another, despite the name, they can be fired at the same time, but end at different time as you want. I'm not sure if it is appropriate to give an answer with just sharing the link to the flutter docs, but here it is https://flutter.dev/docs/development/ui/animations/staggered-animations. I have done something similar, but with 2 controllers, which I fire at the same time, but they have different durations.

Ah, I was second :)

edit: here is some code one with 2 controlers

import 'package:flutter/material.dart';
//import 'package:flutter/scheduler.dart';
import 'package:flutter_color_picker/components/color_ripple.dart';

class ColorKnob extends StatefulWidget {
  const ColorKnob({this.color, this.ratio, this.saveColor});

  final Color color;
  final double ratio;
  final Function saveColor;

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

class _ColorKnobState extends State<ColorKnob> with TickerProviderStateMixin {
  AnimationController scaleAnimationController;
  AnimationController rippleAnimationController;
  Animation<double> scaleAnimation;

  @override
  void initState() {
    super.initState();
    scaleAnimationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 100));

    rippleAnimationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 400));

    scaleAnimationController.addStatusListener((AnimationStatus status) {
      if (status == AnimationStatus.completed) {
        scaleAnimationController.reverse();
      }
    });

    scaleAnimation = Tween<double>(begin: 1.0, end: 0.8).animate(
        CurvedAnimation(
            parent: scaleAnimationController, curve: Curves.easeOut));

    rippleAnimationController.addStatusListener((AnimationStatus status) {
      if (status == AnimationStatus.completed) {
        widget.saveColor();
      }
    });

    scaleAnimation.addListener(() {
      setState(() {});
    });
  }

  @override
  void dispose() {
    super.dispose();
    scaleAnimationController.dispose();
    rippleAnimationController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
          decoration: const BoxDecoration(
              shape: BoxShape.circle, color: Colors.transparent),
          child: FractionallySizedBox(
            widthFactor: widget.ratio,
            heightFactor: widget.ratio,
            child: ClipOval(
              clipBehavior: Clip.antiAlias,
              child: Center(
                child: Stack(children: <Widget>[
                  ColorRipple(
                      controller: rippleAnimationController,
                      color: widget.color,
                  ),
                  GestureDetector(
                    onTap: () {
                      //            timeDilation = 1.0;
                      scaleAnimationController.forward(from: 0.0);
                      rippleAnimationController.forward(from: 0.0);
                    },
                    child: Transform.scale(
                      scale: scaleAnimation.value,
                      alignment: Alignment.center,
                      child: Container(
                        width: 60.0,
                        height: 60.0,
                        decoration: BoxDecoration(
                            shape: BoxShape.circle,
                            color: widget.color,
                            border: Border.all(
                              color: const Color(0xFFFFFFFF),
                              style: BorderStyle.solid,
                              width: 4.0,
                            ),
                            boxShadow: const <BoxShadow>[
                              BoxShadow(
                                offset: Offset(0.0, 1.0),
                                blurRadius: 6.0,
                                spreadRadius: 1.0,
                                color: Color(0x44000000),
                              )
                            ]),
                      ),
                    ),
                  ),
                ]),
              ),
            ),
          )),
    );
  }
}

and one with multiple tweens

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

class ColorRipple extends StatelessWidget {
  ColorRipple({this.controller, this.color, this.size})
      : scaleUpAnimation = Tween<double>(begin: 0.8, end: 5.0).animate(
          CurvedAnimation(
            parent: controller,
            curve: const Interval(
              0.2,
              1.0,
              curve: Cubic(0.25, 0.46, 0.45, 0.94),
            ),
          ),
        ),
        opacityAnimation = Tween<double>(begin: 0.6, end: 0.0).animate(
          CurvedAnimation(
            parent: controller,
            curve: const Interval(
              0.4,
              1.0,
              curve: Cubic(0.25, 0.46, 0.45, 0.94),
            ),
          ),
        ),
        scaleDownAnimation = Tween<double>(begin: 1.0, end: 0.8).animate(
          CurvedAnimation(
            parent: controller,
            curve: const Interval(0.0, 0.2, curve: Curves.easeOut),
          ),
        );

  final AnimationController controller;
  final Animation<double> scaleUpAnimation;
  final Animation<double> scaleDownAnimation;
  final Animation<double> opacityAnimation;
  final Color color;
  final Size size;

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
        animation: controller,
        builder: (BuildContext context, Widget child) {
          return Container(
            child: Transform(
              alignment: Alignment.center,
              transform: Matrix4.identity()
                ..scale(scaleDownAnimation.value)
                ..scale(scaleUpAnimation.value),
              child: Opacity(
                  opacity: opacityAnimation.value,
                  child: Container(
                    width: 60.0,
                    height: 60.0,
                    decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        border: Border.all(
                            color: color,
                            style: BorderStyle.solid,
                            width: 4.0 - (2 * controller.value))),
                  )),
            ),
          );
        });
  }
}
Sign up to request clarification or add additional context in comments.

4 Comments

much aprecciated
@ZlatiP Can I achieve animation one after the other through this, I want to animate a text which FadeIn when the App starts after that when the FadeIn animation is completed I want the next animation to start which is changing the Vertical position of the from 400.0 to 200.0 I am new to flutter so Its very difficult to get around it, Can you please help me " stackoverflow.com/questions/66729188/…"
Thank you. I finished the forward() animation. I want the reverse() is different with the forward(), is that possible? If not, Can I change the Interval time point to different value after click button?
AnimationController has a reverseDuration property and the Animation has reverseCurve you can use those to change the duration and the Interval.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.