GIfatahTH / animator

A Flutter library that makes animation easer. It allows for separation of animation setup from the User Interface.
BSD 3-Clause "New" or "Revised" License
227 stars 28 forks source link

Animator with latest states_rebuilder #38

Closed karnadii closed 4 years ago

karnadii commented 4 years ago

can you update the example with latest states rebuilder?

I am lost. I just want to show and hide an appBar, in debug console it says the animation started but the ui not animatin

import 'package:animator/animator.dart';
import 'package:flutter/material.dart';
import 'package:states_rebuilder/states_rebuilder.dart';
class ReaderService extends StatesRebuilderWithAnimator {
  bool showMenuBar = false;
  init(TickerProvider ticker) {
    animator.tweenMap = {
      "appBarAnim": Tween<double>(
        begin: showMenuBar ? -1 : 0,
        end: showMenuBar ? 0 : -1,
      ),
    };
    initAnimation(ticker);
    addAnimationListener(() {
      rebuildStates(["appBar"]);
    });
    animator.cycles = 1;
    animator.duration = Duration(milliseconds: 200);

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

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

  dispose() {}
}

class ReaderTest extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Injector(
      inject: [Inject(() => ReaderService())],
      builder: (context) {
        var model = Injector.get<ReaderService>();
        return StateWithMixinBuilder(
          mixinWith: MixinWith.tickerProviderStateMixin,
          models: [model],
          initState: (ctx, ticker) => model.init(ticker),
          dispose: (_, ___) => model.dispose(),
          builder: (_, __) => Scaffold(
            body: Stack(
              children: <Widget>[
                Container(
                  child: GestureDetector(
                    onTap: () {
                      model.showMenuBar = !model.showMenuBar;
                      model.rebuildStates(["appBar"]);

                      model.startAnimation(true);
                    },
                  ),
                ),
                StateBuilder(
                    tag: "appBar",
                    models: [model],
                    builder: (_, __) {
                      return Align(
                          alignment: Alignment.topCenter,
                          child: FractionalTranslation(
                            translation: Offset(
                                0, model.animationMap["appBarAnim"].value),
                            child: Container(
                                height: 100,
                                width: double.infinity,
                                color: Colors.red,
                                child: Center(
                                    child: Text("${model.showMenuBar}"))),
                          ));
                    }),
              ],
            ),
          ),
        );
      },
    );
  }
}
GIfatahTH commented 4 years ago

Sorry for may late response! First you have to inverse the order of widget in the Stack, the last one in the top one and you have to put the GestureDetector on top (this is not related to animator)

Second you have to comment the line that defines the duration in the RenerService class. (this is an issue of animator that I will fix.

Meanwhile, I am refactoring animator to and animator keys to the animator widget so you can control the animation from outside the animator widget (as ask here #24),

GIfatahTH commented 4 years ago

Here is your code refactor using AnimatorKey


class ReaderTest extends StatefulWidget {
  @override
  _ReaderTestState createState() => _ReaderTestState();
}

class _ReaderTestState extends State<ReaderTest> {
  bool showMenuBar = false;
  final animatorKey = AnimatorKey();

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Animator(
          animatorKey: animatorKey,
          tweenMap: {
            "appBarAnim": Tween<double>(
              begin: 0,
              end: 1,
            ),
          },
          builderMap: (animationMap) {
            return Align(
                alignment: Alignment.topCenter,
                child: FractionalTranslation(
                  translation:
                      Offset(0, animationMap["appBarAnim"]?.value ?? 0),
                  child: Container(
                      height: 100,
                      width: double.infinity,
                      color: Colors.red,
                      child: Center(child: Text("$showMenuBar"))),
                ));
          },
        ),
        Container(
          child: GestureDetector(
            onTap: () {
              showMenuBar = !showMenuBar;
              animatorKey.refreshAnimation(
                tweenMap: {
                  "appBarAnim": Tween<double>(
                    begin: showMenuBar ? -1 : 0,
                    end: showMenuBar ? 0 : -1,
                  ),
                },
                cycles: 1,
                duration: Duration(seconds: 2),
              );
            },
          ),
        ),
      ],
    );
  }
}
karnadii commented 4 years ago

since I want my appBar to be clickable my stack order is correct.

this is better, thanks.

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool showMenuBar = false;
  final animatorKey = AnimatorKey<double>();
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Container(
          child: GestureDetector(
            onTap: () {
              showMenuBar = !showMenuBar;
              if (showMenuBar) {
                animatorKey.controller.forward();
              } else {
                animatorKey.controller.reverse();
              }
            },
          ),
        ),
        Animator<double>(
          animatorKey: animatorKey,
          tween: Tween<double>(begin: 1, end: 0),
          resetAnimationOnRebuild: false,
          triggerOnInit: false,
          duration: Duration(milliseconds: 200),
          builder: (_, animTop, child) {
            return Align(
                alignment: Alignment.topCenter,
                child: FractionalTranslation(
                  translation: Offset(0, 0 - animTop.value ?? -1),
                  child: Container(
                    height: 100,
                    width: double.infinity,
                    color: Colors.red,
                    child: Center(
                      child: Text("$showMenuBar"),
                    ),
                  ),
                ));
          },
        ),
        AnimatorRebuilder(
          observe: () => animatorKey,
          builder: (ctx, animBottom, child) {
            return Align(
                alignment: Alignment.bottomCenter,
                child: FractionalTranslation(
                  translation: Offset(0, animBottom.value ?? 1),
                  child: Container(
                    height: 200,
                    width: double.infinity,
                    color: Colors.red,
                    child: Center(
                      child: Text("$showMenuBar"),
                    ),
                  ),
                ));
          },
        )
      ],
    );
  }
}