animator 1.0.0+1

animator #

This library is an animation library for Flutter that:

  • makes animation as simple as the simplest widget in Flutter with the help of Animator widget,
  • Allows you to declare all animation setup in your logic classes (BloCs) and animate you widgets.

In flutter animation can be classified:

  • Implicit: such as AnimatedContainer, AnimatedPadding, AnimatedPositioned and AnimatedDefaultTextStyle.
  • Explicit: Where you define AnimationController, Animation and Tween classes, and you should explicitly start, stop and listen to animation status.

Following the same fashion, the Animator package offers implicit-like and explicit-like animation

Implicit-like animation: #

With one widget, Animator, you can do all the available animation in Flutter.

Animator({
    Key key, 
    Tween<dynamic> tween, // (1) // Default tween: Tween<double>(begin:0 end: 1)
    Duration duration: const Duration(milliseconds: 500),  // (2)
    Curve curve: Curves.linear, // (3)
    int cycles, // (4)
    int repeats, // (5)
    (Animation<dynamic>) → Widget builder, // (6)
    Map<String, Tween<dynamic>> tweenMap, // (7)
    (Map<String, Animation<dynamic>>) → Widget builderMap, // (8)
    () → void endAnimationListener, // (9)
    dynamic customListener,  // (10)
    (AnimationStatus, AnimationSetup) → dynamic statusListener //(11)
    bool triggerOnInit: true, () // (12)
    bool resetAnimationOnRebuild: false, // (13)
    String name, // (14)
    List<StatesRebuilder> blocs, // (15)
    TickerMixin tickerMixin, // (16)
})

To implement any type of animation with animator you have to define a Tween (1), Duration (2) and Curve (3). `

With cycles argument (4) you define the number of forward and backward periods you want your animation to perform before stopping.

With repeats argument (5) you define the number of forward periods you want your animation to perform before stopping.

In the builder argument (6) you put your widgets to be animated. The builder is a function with Animation argument.

If you want to animate many Tween, use tweenMap argument (7). Is is a Map of String type keys and Tween type values. In this case you have to use builderMap (8) instead of builder (6).

With endAnimationListener (9) argument you can define a VoidCallback to be executed when animation is finished. For example, it can be used to trigger another animation.

With customListener (10) argument you can define a Function to be called every time the animation value changes. The customListener is provided with an Animation object.

With statusListener (11) argument you can define a Function to be called every time the status of the animation change. The customListener is provided with an AnimationStatus, AnimationSetup objects.

triggerOnInit (12) controls whether the animation is automatically started when Animator widget is initialized. The default value is true.

If you want to reset your animation, such as changing your Tween or duration, and want the new setting to be reconsidered when the Animator widget is rebuilt, set the resetAnimationOnRebuild (13) argument to true. The default value is false.

name is a unique name of your Animator widget. It is used to rebuild this widget from your logic classes.

blocs argument is a list of your logic classes you want to rebuild this widget from. The logic class should extend StatesRebuilderof the states_rebuilder package.

Example of a single Tween animation: #

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

void main() => runApp(AnimatedLogo());

class AnimatedLogo extends StatelessWidget {
  Widget build(BuildContext context) {
    return Animator<double>(
      tween: Tween<double>(begin: 0, end: 300),
      cycles: 0,
      builder: (anim) => Center(
            child: Container(
              margin: EdgeInsets.symmetric(vertical: 10),
              height: anim.value,
              width: anim.value,
              child: FlutterLogo(),
            ),
          ),
    );
  }
}

Example of a multi-tween animation: #

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

void main() => runApp(AnimatedLogo());

class AnimatedLogo extends StatelessWidget {
  Widget build(BuildContext context) {
    return Animator(
      tweenMap: {
        "scaleAnim": Tween<double>(begin: 0, end: 300),
        "translateAnim": Tween<Offset>(begin: Offset.zero, end: Offset(2, 0)),
      },
      cycles: 0,
      builderMap: (anim) => Center(
            child: FractionalTranslation(
              translation: anim["translateAnim"].value,
              child: Container(
                margin: EdgeInsets.symmetric(vertical: 10),
                height: anim["scaleAnim"].value,
                width: anim['scaleAnim'].value,
                child: FlutterLogo(),
              ),
            ),
          ),
    );
  }
}

You can nest many Animator with different setting (tween, duration, curve, repeats and cycles) to do a complex animation:

This is a simple example of how to animate the the scale and rotation independently.

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

void main() => runApp(AnimatedLogo());

class AnimatedLogo extends StatelessWidget {
  Widget build(BuildContext context) {
    return Animator<double>(
      tween: Tween<double>(begin: 0, end: 300),
      repeats: 0,
      duration: Duration(seconds: 2),
      builder: (anim1) => Animator<double>(
        tween: Tween<double>(begin: -1, end: 1),
        cycles: 0,
        builder: (anim2) => Center(
          child: Transform.rotate(
            angle: anim2.value,
            child: Container(
              margin: EdgeInsets.symmetric(vertical: 10),
              height: anim1.value,
              width: anim1.value,
              child: FlutterLogo(),
            ),
          ),
        ),
      ),
    );
  }
}

Use nested Animators with CustomPainter and CustomClipper and draw the animation you want.

Explicit-like animation: #

With implicit-like animation you can implement almost all the available animation type in Flutter. However if you want more control over your animation use Explicit-like animation.

Your logic class should extends StatesRebuilderWithAnimator to get access to animator parameters and your UI should use StateWithMixinBuilder from the states_rebuilder package.

You have many methods available in the logic class:

1- initAnimation : to initialize animation.

void initAnimation([TickerProvider ticker])

3- addAnimationListener: to aAdd listeners you want to calls every time animation ticks.

void addAnimationListener(void Function() fn)

3- addAnimationStatusListener: to aAdd listeners you want to calls every time animation status changes.

void addAnimationStatusListener(void Function(AnimationStatus) fn)

4- endAnimationListener: to aAdd listeners you want to calls The animation ends.

void endAnimationListener(void Function() fn)

3- triggerAnimation : to starts running this animation forwards (towards the end).

void triggerAnimation({bool reset = false})

5- dispose() : to dispose the animation controller.

Implicit animation example: #

 import 'dart:math';
import 'package:flutter/material.dart';
import 'package:animator/animator.dart';
import 'package:states_rebuilder/states_rebuilder.dart';


class MyBloc extends StatesRebuilderWithAnimator {
  init(TickerProvider ticker) {
    animator.tweenMap = {
      "opacityAnim": Tween<double>(begin: 0.5, end: 1),
      "rotationAnim": Tween<double>(begin: 0, end: 2 * pi),
      "translateAnim": Tween<Offset>(begin: Offset.zero, end: Offset(1, 0)),
    };
    initAnimation(ticker);
    addAnimationListener(() {
      print(this);
      rebuildStates(["OpacityWidget", "RotationWidget"]);
    });
    animator.cycles = 3;
    // animator.duration = Duration(seconds: 2);

    endAnimationListener(() => print("animation finished"));
  }

  startAnimation([bool reset = false]) {
    triggerAnimation(reset: reset);
  }
}

class ExplicitAnimation extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Injector<MyBloc>(
      models: [() => MyBloc()],
      builder: (_, model) => Scaffold(
        appBar: AppBar(
          title: Text("Flutter Animation"),
        ),
        body: Padding(
          padding: EdgeInsets.all(20),
          child: StateWithMixinBuilder(
            mixinWith: MixinWith.tickerProviderStateMixin,
            viewModels: [model],
            initState: (ctx, _, ticker) => model.init(ticker),
            dispose: (_, __, ___) => model.dispose(),
            builder: (_, __) => Center(child: MyAnimation()),
          ),
        ),
      ),
    );
  }
}

class MyAnimation extends StatelessWidget {
  final _flutterLog100 =
      FlutterLogo(size: 150, style: FlutterLogoStyle.horizontal);

  final model = Injector.get<MyBloc>();
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      RaisedButton(
        child: Text("Animate"),
        onPressed: () => model.triggerAnimation(),
      ),
      RaisedButton(
        child: Text("Reset and Animate"),
        onPressed: () => model.startAnimation(true),
      ),
      StateBuilder(
        tag: "OpacityWidget",
        blocs: [model],
        builder: (_, __) => FadeTransition(
          opacity: model.animationMap["opacityAnim"],
          child: FractionalTranslation(
            translation: model.animationMap["translateAnim"].value,
            child: _flutterLog100,
          ),
        ),
      ),
      StateBuilder(
        tag: "RotationWidget",
        blocs: [model],
        builder: (_, __) {
          return Container(
            child: FractionalTranslation(
              translation: model.animationMap["translateAnim"].value,
              child: Transform.rotate(
                angle: model.animationMap['rotationAnim'].value,
                child: _flutterLog100,
              ),
            ),
          );
        },
      )
    ]);
  }
}

[1.0.0+1].

  1. Refactor code.
  2. Fix typos.

[1.0.0].

  1. You can nest Animator Widget with different tween, duration and curve.
  2. Refactor code and test it.
  3. Explicit-like animation are used with StateWithMixinBuilder widget.
  4. Update to use states_rebuilder: ^1.5.0.

[0.1.4].

  1. update to use states_rebuilder: ^1.3.2

[0.1.3].

  1. update to use states_rebuilder: ^1.3.1
  2. Fiw typos

[0.1.2].

  1. update to use states_rebuilder: ^1.2.0
  2. resetAnimationOnRebuild default to false.

[0.1.1].

  1. Remove animateOnRebuild and add triggerOnInit.
  2. Improve the logic
  3. Changed stateID to name

[0.1.0].

  1. Extend the functionality of Animator widget by the following arguments:

    • customListener and statusListener: to listen to the animation and animation status;
    • animateOnRebuild and resetAnimationOnRebuild: to control whether the animation should restart or reset when Animator widget is rebuilt;
    • stateID and blocs : to rebuild the Animator widget from the logic blocs using the states_builder package.
  2. Fix some typos and improve the documentation

[0.0.1] - initial release.

example/README.md

import 'package:flutter/material.dart';
import 'package:states_rebuilder/states_rebuilder.dart';
import 'package:animator/animator.dart';

class MainBloc extends StatesRebuilder {
  bool toggleCurve = true;
  rebuild() {
    toggleCurve = !toggleCurve;
    rebuildStates(['widget 1', 'widget 2', 'widget 3']);
  }
}

final mainBloc = MainBloc();

class BasicAnimation0 extends StatelessWidget {
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Basic Animation 0'),
        ),
        body: Body(),
      ),
    );
  }
}

class Body extends StatelessWidget {
  const Body({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text('Widget is animated on rebuild'),
        Animator(
          key: UniqueKey(),
          name: "widget 1",
          blocs: [mainBloc],
          duration: Duration(seconds: 2),
          cycles: 2,
          builder: (anim) => Center(
            child: Transform.scale(
              scale: anim.value,
              child: FlutterLogo(size: 50),
            ),
          ),
        ),
        Divider(),
        Text('Widget is not animated on rebuild'),
        Animator(
          duration: Duration(seconds: 2),
          builder: (anim) => Center(
            child: Transform.scale(
              scale: anim.value,
              child: FlutterLogo(
                size: 50,
                colors: Colors.red,
              ),
            ),
          ),
        ),
        Divider(),
        Text('Animation is reset on rebuild. Curve changes on rebuild'),
        StateBuilder(
          tag: 'widget 3',
          blocs: [mainBloc],
          builder: (_, __) => Animator(
            tickerMixin: TickerMixin.tickerProviderStateMixin,
            duration: Duration(seconds: 2),
            repeats: 1,
            resetAnimationOnRebuild: true,
            curve: mainBloc.toggleCurve ? Curves.linear : Curves.bounceIn,
            builder: (anim) => Center(
              child: Transform.scale(
                scale: anim.value,
                child: FlutterLogo(size: 50),
              ),
            ),
          ),
        ),
        RaisedButton(
          child: Text('Rebuild '),
          onPressed: () => mainBloc.rebuild(),
        )
      ],
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  animator: ^1.0.0+1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:animator/animator.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
95
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
97
Learn more about scoring.

We analyzed this package on Sep 13, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.5.0
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.2

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Format lib/src/animate_map.dart.

Run flutter format to format lib/src/animate_map.dart.

Format lib/src/states_rebuilder_with_animator.dart.

Run flutter format to format lib/src/states_rebuilder_with_animator.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
states_rebuilder ^1.5.0+1 1.5.1
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test