preface

Looking through the portal of Wang Shu’s animation video tutorial recently, I can tell you that his explanation details are in place. Made notes by watching his Flutter animation to explain the chapter.

How to choose the right animation control

An implicit animation

Animated+WidgetName

Widget _buildAnimatedContainer() {
  return Center(
    child: AnimatedContainer(
      alignment: Alignment.center,
      duration: const Duration(milliseconds: 1000),
      height: _height,
      width: 200,
      decoration: BoxDecoration(
        boxShadow: const [BoxShadow(spreadRadius: 25, blurRadius: 25)],
        borderRadius: BorderRadius.circular(150),
        gradient: const LinearGradient(
          begin: Alignment.bottomCenter,
          end: Alignment.topCenter,
          colors: [Colors.blue, Colors.white],
          stops: [0.2.0.3],
        ),
      ),
      child: AnimatedSwitcher(
        duration: const Duration(milliseconds: 1000),
        transitionBuilder: (child, animation) {
          return ScaleTransition(
            scale: animation,
            child: FadeTransition(
              opacity: animation,
              child: child,
            ),
          );
        },
        child: _height >= 500
            ? null
            : Center(
                key: ValueKey(_height),
                child: Text(
                  "zhengzeqin $_height",
                  style: TextStyle(
                    fontSize: 18,
                    color: Colors.black,
                  ),
                ),
              ),
      ),
    ),
  );
}
Copy the code

AnimatedContainer

  • Only properties under AnimatedContainer are involved in the animation changes; property changes in child’s widget are not

AnimatedSwitcher

  • The AnimatedSwitcher component is used to perform the switching functions of animation components, such as zooming in on A and zooming in on B, and to cause animation when the child component key or component type changes (see key usage section).
  • AnimatedSwitcher Child if equal to null will lose privacy, default FadeTransition gradient animation
  • TransitionBuilder supports composing multiple animation components like ScaleTransition nested FadeTransition (similar to AnimatedCrossFade in and out)

Related components are

  • AnimatedSwitcher
  • AnimationPadding
  • AnimatedOpacity
  • AnimatedAlign
  • .
AnimatedSwitcher(
  duration: const Duration(milliseconds: 1000),
  transitionBuilder: (child, animation) {
    return ScaleTransition(
      scale: animation,
      child: FadeTransition(
        opacity: animation,
        child: child,
      ),
    );
  },
  child: _height >= 500 ? null : Center(
    key: ValueKey(_height),
    child: Text(
      "zhengzeqin $_height",
      style: TextStyle(
        fontSize: 18,
        color: Colors.black,
      ),
    ),
  ),
)
Copy the code

Implicit animations have a curve

/// More animations and curves
/// Implicit animations have a curve curve. BounceOut, // the elastic end
/// The official document: https://api.flutter-io.cn/flutter/animation/Curves-class.html
Widget _buildAnimated() {
  return Center(
    child: AnimatedPadding(
      curve: Curves.bounceOut, // Elastic end
      duration: Duration(milliseconds: 1000),
      padding: EdgeInsets.only(top: _height),
      child: AnimatedOpacity (
        curve: Curves.bounceInOut, // Elastic start and end
        duration: Duration(milliseconds: 2000),
        opacity: _opacity,
        child: Container(
          height: 300,
          width: 300,
          color: Colors.blue,
        ),
      ),
    ),
  );
}
Copy the code

Keyframe animation Tween

  • TweenAnimationBuilder
  • Begin: 0.0, end: 1.0
    • Note: The keyframe animation changes from the current value to the target value, such as setting 0 -> 100. If the current value is 10, it is from 10 -> 100
  • Translation: the Transform. The translate
    • Offset: offset (0,0) -> offset (-x, -x). It’s center to the bottom right
  • Zoom: Transform scale
    • Scale: 0.0 – > 1.0
  • Rotation: Transform. Rotate
    • Angle: 0.0 -> 6.28. Rotate a circle

/// Between, keyframe animation
Widget _buildTweenAnimated() {
  return Center(
    child: TweenAnimationBuilder(
      duration: Duration(seconds: 1),
      builder: (BuildContext context, double value, Widget? child) {
        return Opacity(
          opacity: value,
          child: Container(
            alignment: Alignment.center,
            height: 300,
            width: 300,
            color: Colors.blue,
            child: Transform.rotate(
              angle: value * 6.28.// a 6.28 lap p is 3.14 1/2 laps
              child: Text(
                "zhengzeqin",
                style: TextStyle(fontSize: 10 + 10 * value),
              ),
            ),
          ),
        );
      },
      tween: Tween<double>(begin: 0.0, end: 1.0),),); }Copy the code

Example: flipped counters

  • The flip is achieved by TweenAnimationBuilder keyframe animation combined with the maneuver of the position


/// Package counter
class TWAnimatedCounter extends StatelessWidget {
  final Duration? duration;
  final double fontSize;
  final double count;

  const TWAnimatedCounter({
    Key? key,
    this.duration,
    this.fontSize = 100.this.count = 0,}) :super(key: key);

  @override
  Widget build(BuildContext context) {
    return TweenAnimationBuilder(
      duration: duration ?? const Duration(seconds: 1),
      tween: Tween(end: count),
      builder: (BuildContext context, double value, Widget? child) {
        final whole = value ~/ 1; / / is rounded
        final decimal = value - whole; / / get the decimal
        return Stack(
          alignment: Alignment.center,
          children: [
            Positioned(
              top: -fontSize * decimal, / / 0 - > - 100
              child: Opacity(
                opacity: 1.0 - decimal, / / 1.0 - > 0.0
                child: Text(
                  "$whole",
                  style: TextStyle(
                    fontSize: fontSize,
                  ),
                ),
              ),
            ),
            Positioned(
              top: fontSize - decimal * fontSize, / / 100 - > 0
              child: Opacity(
                opacity: decimal, / / 0 - > 1.0
                child: Text(
                  "${whole + 1}", style: TextStyle( fontSize: fontSize, ), ), ), ), ], ); }); }}Copy the code

According to the animation

WidgetName + Transition

SingleTickerProviderStateMixin

  • Ticker is every time it refreshes. 60 Hz Triggers 60 times per second

AnimationController

  • Reset: resets the recovery
  • Stop: stop
  • Forward: Executes the command once
  • Repeat: Repeat the execution
  • Reverse: reverse
  • LowerBound -> upperBound defaults to 0 -> 1

Related components are

  • RotationTransition
  • FadeTransition
  • ScaleTransition
  • .
/// Inherit the Animation<double>
class AnimationController extends Animation<double> {
  / / ` ` `
}

_controller = AnimationController(
  // upperBound: 10,
  // lowerBound: 1,
  vsync: this.// Vsync
  duration: const Duration(milliseconds: 1000)); _controller.addListener(() {print("${_controller.value}");
});


/// Call setState
setState(() {
  if (_isLoading) {
    _controller.stop(); // reset: resets recovery stop: pauses
  } else {
    _controller.repeat(reverse: true); // forward: repeat: repeat} _isLoading = ! _isLoading; });Copy the code

/// Rotating animation
Widget _buildRotationTransition() {
  return Center(
    child: RotationTransition(
      turns: _controller,
      child: const Icon(
        Icons.refresh,
        size: 100,),),); }/// Opacity gradient animation
Widget _buildFadeTransition() {
  return Center(
    child: FadeTransition(
      opacity: _controller, / / transparency
      child: Container(
        height: 100,
        width: 100,
        color: Colors.blue,
      ),
    ),
  );
}

/// Zoom animation
Widget _buildScaleTransition() {
  return Center(
    child: ScaleTransition(
      scale: _controller, // Scale multiple
      child: Container(
        height: 100,
        width: 100,
        color: Colors.yellow,
      ),
    ),
  );
}
Copy the code

Keyframe animation Tween

  • Through _controller. Drive (Tween (…). Add Tween keyframe start and end values.
  • The equivalent is Tween(…) .animate(_controller)
  • Chain superimposed with a CurveTween(Curve: Interval(0.8, 1.0)) means that the animation is not executed before 80% of the time, and the animation is completed in the remaining 20% of the time
  • Chain adds a CurveTween(Curve: Curves).bounceInOut) means that the dynamic effect of adding an elastic in and out
  • Note that the superposition of the animation is functionally similar: g(f(x))
  • In the Slide Slide animation, offset is the origin of (0,0). An offset of 0.5 is a multiple of 0.5
Widget _buildTweenAnimation() {
  return SlideTransition(
    child: Container(
      height: 100,
      width: 100,
      color: Colors.red,
    ),
    position: Tween(
      begin: const Offset(0.0),
      end: const Offset(0.5.1),
    )
        .chain(
          CurveTween(
            curve: const Interval(0.8.1.0),// Curves.bounceOut
          ),
        )
        .animate(_controller),
    // position: _controller.drive(
    // Tween(
    // begin: const Offset(0, 0),
    // end: const Offset(0.5, 1),
    / /),
    // ),
  );
}
Copy the code

Case study: interlaced animation

/// Staggered animation
class TWSlidingBox extends StatelessWidget {
  final AnimationController controller;
  final Color color;
  final Interval interval;

  const TWSlidingBox({
    Key? key,
    required this.controller,
    required this.color,
    required this.interval,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      child: Container(
        width: 300,
        height: 100,
        color: color,
      ),
      position: Tween(
        begin: Offset.zero,
        end: const Offset(0.1.0),
      )
          .chain(
            CurveTween(curve: interval),
          )
          .chain(
            CurveTween(curve: Curves.bounceInOut),   // g(f(x))) .animate(controller), ); }}Copy the code

Custom animation

/// Custom animation
  Widget _buildCustomAnimation() {
    final Animation opacityAnimation = Tween(begin: 0.5, end: 0.8).animate(_controller);
    final Animation heightAnimation = Tween(begin: 100.0, end: 200.0).animate(_controller);
    return AnimatedBuilder(
      animation: _controller,
      child: const Text("Custom Animation",textAlign: TextAlign.center,), // This child is passed to the Builder for performance reasons
      builder: (BuildContext context, Widget? child) {
        return Opacity(
          opacity: opacityAnimation.value,
          child: Container(
            alignment: Alignment.center,
            color: Colors.blue,
            width: 100, height: heightAnimation.value, child: child, ), ); }); }Copy the code

Case study: animation of 478 breathing method

  • Note if you use multiple AnimationController requires with TickerProviderStateMixin, is SingleTickerProviderStateMixin under a single
  • Leave the animation in wait by await future.delayed

void handleBreatedAnimation() async {
  _expansionController.duration = const Duration(seconds: 4);
  _expansionController.forward();
  await Future.delayed(const Duration(seconds: 4));

  _opacityController.duration = const Duration(milliseconds: 1750);
  _opacityController.repeat(reverse: true);
  await Future.delayed(const Duration(seconds: 7));
  _opacityController.reset();

  _expansionController.duration = const Duration(seconds: 8);
  _expansionController.reverse();
}

Widget _buildBreatedAnimation() {
  // _controller.duration = const Duration(seconds: 20);
  // Animation animation1 = Tween(begin: 0.0, end: 1.0)
  //. Chain (curve: const Interval(0.1, 0.2))
  // .animate(_controller);
  // Animation animation2 = Tween(begin: 1.0, end: 0.0)
  //. Chain (curve: const Interval(0.4, 0.95))
  // .animate(_controller);
  return FadeTransition(
    opacity: Tween(begin: 0.5, end: 1.0).animate(_opacityController),
    child: AnimatedBuilder(
      // animation: _controller,
      animation: _expansionController,
      builder: (BuildContext context, Widget? child) {
        return Container(
          width: 300,
          height: 300,
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: Colors.blue,
            gradient: RadialGradient(
              colors: [
                Colors.blue[600]! , Colors.blue[100]! , ], stops: [ _expansionController.value, _expansionController.value +0.1[, (), (), (); },),); }Copy the code

conclusion

Animation. Xmind

reference

  • Demo
  • Uncle Wang is not bald – animation tutorial
  • Official curve curvature
  • How to make scrolling counter in flutter