How to define discrete animation in Flutter?

2019-05-22 11:46发布

问题:

Is it possible to create an animation in flutter that doesn't continously change its value, but only with a given time gaps?

I have the following code working right now, but i'm sure there is a better solution out there.

  int aniValue = 0;
  bool lock = false;
  _asyncFunc() async {
    if(lock) return;
    else     lock = true;

    await new Future.delayed(const Duration(milliseconds: 50), () {
      ++aniValue;

      if (aniValue == 41) {
        aniValue = 0;
      }
    });

    lock = false;

    setState(() {});
    _asyncFunc();
  }

回答1:

It is possible to define a Curve to animations; to have non-linear progression.

Flutter doesn't provides a "step" curves, but you can make one fairly easily:

class StepCurve extends Curve {
  final int stepCount;

  const StepCurve([this.stepCount = 2]) : assert(stepCount > 1);

  @override
  double transform(double t) {
    final progress = (t * stepCount).truncate();
    return 1 / (stepCount - 1) * progress;
  }
}

You can then freely use it by associating it to a CurveTween:

@override
Widget build(BuildContext context) {
  return AlignTransition(
    alignment: AlignmentGeometryTween(
      begin: Alignment.centerLeft,
      end: Alignment.centerRight,
    )
        .chain(CurveTween(curve: const StepCurve(5)))
        .animate(animationController),
    child: Container(
      color: Colors.red,
      width: 42.0,
      height: 42.0,
    ),
  );
}


Another solution is using TweenSequence.

class TestAnim extends StatefulWidget {
  @override
  _TestAnimState createState() => _TestAnimState();
}

class _TestAnimState extends State<TestAnim>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 1),
    )..repeat();
  }

  @override
  Widget build(BuildContext context) {
    final colors = <Color>[
      Colors.red,
      Colors.blue,
      Colors.lime,
      Colors.purple,
    ];

    return DecoratedBoxTransition(
      decoration: TweenSequence(colorsToTween(colors).toList())
          .animate(animationController),
      child: const SizedBox.expand(),
    );
  }
}

Iterable<TweenSequenceItem<Decoration>> colorsToTween(
    List<Color> colors) sync* {
  for (int i = 0; i < colors.length - 1; i++) {
    yield TweenSequenceItem<Decoration>(
      tween: DecorationTween(
        begin: BoxDecoration(color: colors[i]),
        end: BoxDecoration(color: colors[i + 1]),
      ),
      weight: 1.0,
    );
  }
}