simple_animations

repository·main·Indexed 21 days ago

https://github.com/felixblaschke/simple_animations

A Flutter package for creating custom, complex, and staggered animations. It features high-level builder widgets (PlayAnimationBuilder, LoopAnimationBuilder, MirrorAnimationBuilder), a timeline-based MovieTween system for combining multiple tweens into sequences, and an AnimationMixin to reduce AnimationController boilerplate in StatefullWidgets. It also includes Animation Developer Tools for debugging and fine-tuning playback.

Tokens
14.7K
Snippets
40
Records
44
Agent score
77%

What's inside simple_animations

  1. Use MovieTween to combine multiple animations

    main

    A MovieTween allows you to combine multiple tweens into a single timeline with control over timing and value extrapolation. You can define multiple properties (like 'width' or 'height') within the same MovieTween instance.

    To use it, create a MovieTween and call .tween() for each property. You can use the cascade operator (..) for a builder-style syntax. To create staggered animations where one property follows another, use .thenTween().

    final tween = MovieTween()
      ..tween(
        'width',
        Tween(begin: 0.0, end: 100.0),
        duration: const Duration(milliseconds: 700),
      )
      ..thenTween(
        'width',
        Tween(begin: 100.0, end: 200.0),
        duration: const Duration(milliseconds: 500),
      );
  2. Understand MovieTween value extrapolation

    main

    If a property is not explicitly tweened for a specific time range in the MovieTween timeline, the values are extrapolated:

    • Before the first tween: The property uses the first value defined in its first tween.
    • After the last tween: The property maintains its last defined value.

    Note: You can only access properties that were explicitly part of the MovieTween. Accessing an un-tweened property will result in an error.

  3. Core concepts of the Animation Builder

    main

    To create an animation using the Animation Builder system, you must define three essential components:

    1. tween: Defines what value is changing (e.g., a color or a double) and the range (from A to B). It does not define the speed.
    2. duration: Defines how long the animation takes.
    3. builder: A function that defines how the UI responds to the changing value. It is called for every newly rendered frame.

    The builder function accepts three parameters:

    • context: The Flutter BuildContext.
    • value: The current value produced by the tween (e.g., a double between the begin and end values).
    • child: An optional widget passed to the builder that remains constant and does not rebuild, which helps optimize performance.

    All Animation Builder widgets support an optional fps parameter to limit the rebuild rate, which is useful for expensive animations.

    import 'package:flutter/material.dart';
    
    // Animate a color from red to blue
    var colorTween = ColorTween(begin: Colors.red, end: Colors.blue);
    
    // Animate a double value from 0 to 100
    var doubleTween = Tween<double>(begin: 0.0, end: 100.0);
  4. Manage scenes in MovieTween

    main

    A MovieTween is composed of one or more scenes. Each scene can contain multiple property tweens.

    Creating Scenes

    • Implicitly: Calling .tween() or .thenTween() automatically creates a new scene.
    • Explicitly: Use .scene() to define a new scene or .thenFor() to create a scene that follows another.

    Scene Positioning

    • Absolute Scenes: Use .scene() with begin and end (or begin and duration) to place a scene at a specific point in the timeline.
    • Relative Scenes: Use .thenFor() on an existing scene to create a new scene that starts after the previous one, optionally with a delay.

    Overlapping

    While you can overlap tweens for the same property, it is generally recommended to use non-overlapping scenes for easier maintenance.

    // Absolute scene example
    final scene2 = tween.scene(
      begin: const Duration(milliseconds: 200),
      duration: const Duration(milliseconds: 700),
    );
    
    // Relative scene example
    final secondScene = firstScene.thenFor(
      delay: const Duration(milliseconds: 200),
      duration: const Duration(seconds: 2),
    ).tween('x', ConstantTween<int>(1));
  5. Animate multiple properties with MovieTween

    main

    The MovieTween class allows you to orchestrate complex animations by defining multiple 'scenes' that control different properties over a timeline. You can specify a begin time or a duration for each scene. Within a scene, you can call .tween() to map a property name (as a string or a MovieTweenProperty) to a specific Tween value.

    To use it, pass the MovieTween instance to a PlayAnimationBuilder or LoopAnimationBuilder. Inside the builder function, retrieve the current values using value.get('propertyName') for string keys, or property.from(value) if using typed MovieTweenProperty objects.

    final MovieTween tween = MovieTween()
      ..scene(begin: const Duration(milliseconds: 0), end: const Duration(milliseconds: 1000))
        .tween('width', Tween(begin: 0.0, end: 100.0))
      ..scene(begin: const Duration(milliseconds: 0), duration: const Duration(milliseconds: 2500))
        .tween('color', ColorTween(begin: Colors.red, end: Colors.blue));
    
    // In the builder:
    PlayAnimationBuilder<Movie>(
      tween: tween,
      duration: tween.duration,
      builder: (context, value, child) {
        return Container(
          width: value.get('width'),
          color: value.get('color'),
        );
      },
    );
  6. Create complex timelines with Movie Tween

    main

    A MovieTween allows you to combine multiple tweens into a single timeline. This is useful for creating staggered animations or complex sequences where multiple properties (like width, height, and color) change at different times.

    You can define animations using:

    • .tween(): Adds a tween to the timeline.
    • .thenTween(): Chains a tween to follow the previous one immediately.
    • .scene(): Defines a specific time segment (start and duration/end) within the timeline to group tweens.
    • MovieTweenProperty<T>: Provides a type-safe way to reference properties within the tween.
    // Staggered tween pattern
    final tween1 = MovieTween()
      ..tween(
        'width',
        Tween(begin: 0.0, end: 100),
        duration: const Duration(milliseconds: 1500),
        curve: Curves.easeIn,
      ).thenTween(
        'width',
        Tween(begin: 100, end: 200),
        duration: const Duration(milliseconds: 750),
        curve: Curves.easeOut,
      );
    
    // Scene-based composition
    final tween2 = MovieTween()
      ..scene(
            begin: const Duration(milliseconds: 0),
            duration: const Duration(milliseconds: 500),
          )
          .tween('width', Tween<double>(begin: 0.0, end: 400.0))
          .tween('height', Tween<double>(begin: 500.0, end: 200.0))
      ..scene(
        begin: const Duration(milliseconds: 700),
        end: const Duration(milliseconds: 1200),
      ).tween('width', Tween<double>(begin: 400.0, end: 500.0));
    
    // Type-safe usage
    final width = MovieTweenProperty<double>();
    final tween3 = MovieTween()..tween<double>(width, Tween(begin: 0.0, end: 100));
  7. Debug animations with AnimationDeveloperTools

    main

    The AnimationDeveloperTools widget provides a toolbar to inspect, slow down, and manually scrub through animations.

    To use it:

    1. Wrap your UI (or a high-level part of your widget tree) with AnimationDeveloperTools.
    2. Use the position parameter to place the toolbar (AnimationDeveloperToolsPosition.top, AnimationDeveloperToolsPosition.bottom, or hidden).

    Connecting Animation Builders

    Set the developerMode: true parameter on any of the following Animation Builder widgets to connect them to the nearest AnimationDeveloperTools:

    • PlayAnimationBuilder
    • LoopAnimationBuilder
    • MirrorAnimationBuilder
    • CustomAnimationBuilder

    When developerMode is active, the toolbar drives the animation, and normal playback instructions (like delay) are ignored.

    Connecting AnimationMixin

    If using AnimationMixin, call enableDeveloperMode(controller) inside initState() to connect your managed controller to the tools.

    // Example: Connecting an Animation Builder to DevTools
    AnimationDeveloperTools(
      child: Center(
        child: PlayAnimationBuilder<double>(
          tween: Tween<double>(begin: 0.0, end: 100.0),
          duration: const Duration(seconds: 1),
          developerMode: true, // Connects to the parent AnimationDeveloperTools
          builder: (context, value, child) {
            return Container(width: value, height: value, color: Colors.blue);
          },
        ),
      ),
    )
    
    // Example: Connecting AnimationMixin to DevTools
    @override
    void initState() {
      size = Tween<double>(begin: 0.0, end: 100.0).animate(controller);
      enableDeveloperMode(controller); // Connects the managed controller
      controller.forward();
      super.initState();
    }
  8. Use AnimationMixin in a StatefulWidget

    main

    The AnimationMixin provides a built-in AnimationController (accessible via the controller property) to your State class. This is ideal for simple, single-controller animations within a StatefulWidget.

    1. Add with AnimationMixin to your State class.
    2. In initState, create your Animation by calling .animate(controller) on a Tween.
    3. Call controller.play() to start the animation.
    4. Access the current value via animationVariable.value in the build method.
    class _MyAnimatedWidgetState extends State<MyAnimatedWidget>
        with AnimationMixin {
      late Animation<double> size;
    
      @override
      void initState() {
        size = Tween(begin: 0.0, end: 200.0).animate(controller);
        controller.play();
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(width: size.value, height: size.value, color: Colors.red);
      }
    }
  9. Customize iOS Launch Screen Assets

    main

    To change the launch screen image for the iOS version of the application, you must replace the image files located in the ios/Runner/Assets.xcassets/LaunchImage.imageset/ directory with your own assets.

    Alternatively, you can manage these assets using Xcode:

    1. Open the iOS project workspace using open ios/Runner.xcworkspace.
    2. In the Xcode Project Navigator, navigate to Runner/Assets.xcassets.
    3. Drag and drop your desired images into the asset catalog to replace the existing launch images.
    open ios/Runner.xcworkspace
  10. Use Animation Developer Tools to debug animations

    main

    The Animation Developer Tools widget provides a UI for fine-tuning animations. It allows you to:

    • Pause the animation at any point.
    • Scrub through the animation timeline.
    • Speed up or slow down playback.
    • Focus on specific parts of an animation sequence.
  11. Manage AnimationControllers with AnimationMixin

    main

    The AnimationMixin is used in StatefulWidget states to automate the management of AnimationController instances. It removes the boilerplate of manually creating, initializing, and disposing of controllers.

    When you add with AnimationMixin to your State class, a controller instance is automatically provided and wired up. You can then connect your tweens to this controller using the .animate(controller) method.

    class _MyWidgetState extends State<MyWidget> with AnimationMixin {
      late Animation<double> size;
    
      @override
      void initState() {
        // 'controller' is provided by AnimationMixin
        size = Tween<double>(begin: 0.0, end: 200.0).animate(controller);
        controller.play(); 
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(width: size.value, height: size.value, color: Colors.red);
      }
    }
  12. Animate with MovieTween using PlayAnimationBuilder

    main

    To bring a MovieTween to life in a Flutter widget, use the PlayAnimationBuilder<Movie> widget. Pass the MovieTween instance to the tween parameter and use tween.duration for the duration parameter. Inside the builder, use the value.get('propertyName') method to retrieve the current animated value for a specific key.

    @override
    Widget build(BuildContext context) {
      var tween = MovieTween()
        ..scene(duration: const Duration(milliseconds: 700))
            .tween('width', Tween<double>(begin: 0.0, end: 100.0))
            .tween('height', Tween<double>(begin: 300.0, end: 200.0));
    
      return PlayAnimationBuilder<Movie>(
        tween: tween,
        duration: tween.duration,
        builder: (context, value, _) {
          return Container(
            width: value.get('width'),
            height: value.get('height'),
            color: Colors.yellow,
          );
        },
      );
    }