Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems with multiple tween animations in Flutter - Videos Included

Tags:

I have a weird flutter issue with a certain animation I'm trying to create.

I am trying to animate an image onto the screen. I want it to move on the x-axis, and I want it to slowly fade in as well.

So I figured - Positioned and Opacity, and animate their value with a tween.

Both the Positioned and Opacity widgets work great on their own, but when I combine the two - I get a weird animation, that only starts to draw after a while (about 3 seconds).

I tried printing the animation.value and it seems to be fine, slowly climbing from 0.0 to 1.0 - but the clouds suddenly appear only after like 3 seconds.

I tried separating them to different controllers, thought that maybe somehow that was the culprit, but nope.

TLDR Videos:

Opacity Animation Only

Positioned Animation Only

Both Animations Combined - NOT GOOD

Here's the widget's code:

import 'package:app/weather/widgets/CloudProperties.dart';
import 'package:flutter/widgets.dart';

class WeatherCloudWidget extends StatefulWidget {
  final double sunSize;
  final CloudProperties properties;

  WeatherCloudWidget({Key key, this.properties, this.sunSize})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => _WeatherCloudWidget();
}

class _WeatherCloudWidget extends State<WeatherCloudWidget>
    with TickerProviderStateMixin {
  AnimationController controller;
  AnimationController controller2;

  Animation<double> position;
  Animation<double> opacity;

  @override
  initState() {
    super.initState();
    _startAnimation();
  }

  @override
  Widget build(BuildContext context) {
    // screen width and height
    final screenWidth = MediaQuery.of(context).size.width;
    final screenHeight = MediaQuery.of(context).size.height;

    final properties = widget.properties;

    var vertical =
        screenHeight * 0.5 + (widget.sunSize * properties.verticalOffset * -1);

    var horizontal = (screenWidth * 0.5) + (widget.sunSize * position.value);

    print(opacity.value);

    // both Positioned & Opacity widgets

    return Positioned(
        left: horizontal,
        top: vertical,
        child: Opacity(
          opacity: opacity.value,
          child: Image.asset(
            properties.path,
            width: properties.getScaledWidth(widget.sunSize),
            height: properties.getScaledHeight(widget.sunSize),
          ),
        ));

    // Positioned only

    return Positioned(
        left: horizontal,
        top: vertical,
        child: Image.asset(
          properties.path,
          width: properties.getScaledWidth(widget.sunSize),
          height: properties.getScaledHeight(widget.sunSize),
        ));

    // Opacity only

    return Positioned(
        left: (screenWidth * 0.5) + (widget.sunSize * properties.tween[1]),
        top: vertical,
        child: Opacity(
          opacity: opacity.value,
          child: Image.asset(
            properties.path,
            width: properties.getScaledWidth(widget.sunSize),
            height: properties.getScaledHeight(widget.sunSize),
          ),
        ));
  }

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

  void _startAnimation() {
    controller = AnimationController(
        duration: const Duration(milliseconds: 5000), vsync: this);

    controller2 = AnimationController(
        duration: const Duration(milliseconds: 5000), vsync: this);

    position = Tween(
            begin: widget.properties.tween[0], end: widget.properties.tween[1])
        .animate(
            new CurvedAnimation(parent: controller, curve: Curves.decelerate))
          ..addListener(() => setState(() {}));

    opacity = Tween(begin: 0.0, end: 1.0).animate(controller2)
      ..addListener(() => setState(() {}));

    controller.forward();
    controller2.forward();
  }
}
like image 782
dasfima Avatar asked Nov 18 '18 19:11

dasfima


People also ask

What are staggered animations?

A staggered animation consists of sequential or overlapping animations. To create a staggered animation, use multiple Animation objects. One AnimationController controls all of the Animation s. Each Animation object specifies the animation during an Interval . For each property being animated, create a Tween .

What is the refresh rate of our animation in Flutter?

In reality, Flutter is running this example at ~60 frames per second.

How do you use tween animation in Flutter?

Tween. AnimationController controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this); Animation<int> alpha = IntTween(begin: 0, end: 255). animate(controller); Note: The animate() method returns an Animation , not an Animatable .

How do you repeat an animation in Flutter?

For example, we can repeat an animation using controller. repeat(). Note, however, that the Flutter animations we create are not tied to a specific object but rather, any widget in the hierarchy can use it as the need be. That's it!


1 Answers

Alright guys. I managed to sort this using SlideTransition and FadeTransition. I guess we should only use Transition widgets for... transitions? while things like Positioned and Opacity are for more static widgets? Not sure...

What it looks like: https://youtu.be/hj7PkjXrgfg

Anyways, here's the replacement code, if anyone's looking for reference:

class WeatherCloudWidget extends StatefulWidget {
  final double sunSize;
  final CloudProperties properties;

  WeatherCloudWidget({Key key, this.properties, this.sunSize})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => _WeatherCloudWidget();
}

class _WeatherCloudWidget extends State<WeatherCloudWidget>
    with TickerProviderStateMixin {
  AnimationController controller;
  Animation<Offset> position;
  Animation<double> opacity;

  final alphaTween = new Tween(begin: 0.0, end: 1.0);

  @override
  initState() {
    super.initState();
    _startAnimation();
  }

  @override
  Widget build(BuildContext context) {
    // screen width and height
    final screenWidth = MediaQuery.of(context).size.width;
    final screenHeight = MediaQuery.of(context).size.height;

    final properties = widget.properties;

    var vertical = (screenHeight * 0.5) +
        (widget.sunSize * properties.verticalOffset * -1);

    var horizontal =
        (screenWidth * 0.5) + (widget.sunSize * properties.tweenEnd);

    return Positioned(
      left: horizontal,
      top: vertical,
      child: SlideTransition(
          position: position,
          child: FadeTransition(
            opacity: opacity,
            child: Image.asset(
              properties.path,
              width: properties.getScaledWidth(widget.sunSize),
              height: properties.getScaledHeight(widget.sunSize),
            ),
          )),
    );
  }

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

  void _startAnimation() {
    controller = AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);

    position = new Tween<Offset>(
      begin: new Offset(widget.properties.tweenStart, 0.0),
      end: new Offset(0.0, 0.0),
    ).animate(new CurvedAnimation(parent: controller, curve: Curves.decelerate));

    opacity = alphaTween.animate(controller);

    controller.forward();
  }
}
like image 84
dasfima Avatar answered Oct 04 '22 20:10

dasfima