flutter3.0学习笔记

AnimationController

Preview
  • AnimationController
  • 创建了一个Animation对象
  • 添加SingleTickerProviderStateMixin
  • 定义一个 AnimationController
  • 实例化创建这个_controller 的方法
  • 构建页面UI

AnimationController

在 Flutter 中,我们基本上有两种类型的动画:隐式和显式。隐式动画是 Fluter SDK 中可用的预构建动画,显式动画需要一个controller来执行动画。其构造函数:

 AnimationController({
    double? value,
    this.duration,
    this.reverseDuration,
    this.debugLabel,
    this.lowerBound = 0.0,//区间
    this.upperBound = 1.0,//区间
    this.animationBehavior = AnimationBehavior.normal,
    required TickerProvider vsync,//TickerProvider类型,必须添加SingleTickerProviderStateMixin
  })

AnimationController提供了很多方法:

  • forward: 动画将从lowerBound到upperBound。
  • reverse: 动画将从upperBound到lowerBound。
  • repeat: 动画将从lowerBound到upperBound和从upperBound到重复loweBound。
  • stop:动画将停止运行。
  • reset: 动画会回到初始状态。 AnimationController会在动画的每一帧,就会生成一个新的值。默认情况下,AnimationController在给定的时间段内线性的生成从 0.0 到1.0(默认区间)的数字。

创建了一个Animation对象

final controller = AnimationController(
     duration: const Duration(seconds: 2),
     //生成数字的区间可以通过lowerBound和upperBound来指定
     lowerBound: 10.0,
     upperBound: 20.0,
     vsync: vsync
 );

创建AnimationController时,需要传递一个vsync参数,vsync参数可防止屏幕外动画消耗不必要的资源。我们可以将SingleTickerProviderStateMixin添加到State的定义中,然后将State对象作为vsync的值。下面我们来举个例子

添加SingleTickerProviderStateMixin

class _AnimationPageState extends State<AnimationPage> with SingleTickerProviderStateMixin{
...
}

定义一个 AnimationController

class _AnimationPageState extends State<AnimationPage> with SingleTickerProviderStateMixin{
  late AnimationController _controller;
}

实例化创建这个_controller 的方法

@override
  void initState() {
    // TODO: implement initState
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
        vsync: this,
    );
  }

以上,我们通过两个参数来实例化类

  • duration:这是此动画应持续的总时间长度。
  • vsync: 一个TickerProvider是必需的。因此,我们必须用SingleTickerProviderMixin。 在这种情况下,值 this 仅指类的 current context。

构建页面UI

import 'package:flutter/material.dart';

class AnimationPage extends StatefulWidget {
  const AnimationPage({Key? key}) : super(key: key);

  @override
  State<AnimationPage> createState() => _AnimationPageState();
}

class _AnimationPageState extends State<AnimationPage> with SingleTickerProviderStateMixin{
  late AnimationController _controller;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    //创建动画控制器
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
        vsync: this,
    );
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Animation'),),
      body: Stack(
        children: [
          Image.asset(
            'images/qiuc.jpeg',
            fit: BoxFit.cover,
            height: double.infinity,
            width: double.infinity,
          ),
          Transform.translate(
            offset: const Offset(250,300),
            child: Image.asset(
              'images/qiu.png',
              fit: BoxFit.contain,
              height: 70,
              width: 70,
            ),
          )
        ],
      ),
    );
  }
}

Simulator Screen Shot - iPhone 14 Pro - 2022-11-30 at 23.28.39.png

现在要从上到下和从下到上移动篮球,为此,我们需要调用repeat方法,并且需要更新球的偏移量。

完整代码:

import 'package:flutter/material.dart';

class AnimationPage extends StatefulWidget {
  const AnimationPage({Key? key}) : super(key: key);

  @override
  State<AnimationPage> createState() => _AnimationPageState();
}

class _AnimationPageState extends State<AnimationPage> with SingleTickerProviderStateMixin{
  late AnimationController _controller;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    //创建动画控制器
    _controller = AnimationController(
      duration: const Duration(milliseconds: 500),
      vsync: this,
      upperBound: 650,
      lowerBound: 400,

    );
    //添加动画执行刷新监听
    _controller.addListener(() {
      setState(() {

      });
    });
    //调用repeat方法
    _controller.repeat(reverse: true);
  }

  @override
  void dispose() {
    // TODO: implement dispose
    _controller.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Animation'),),
      body: Stack(
        children: [
          Image.asset(
            'images/qiuc.jpeg',
            fit: BoxFit.cover,
            height: double.infinity,
            width: double.infinity,
          ),
          Transform.translate(
            offset:  Offset(250,_controller.value),//改变y的偏移量
            child: Image.asset(
              'images/qiu.png',
              fit: BoxFit.contain,
              height: 70,
              width: 70,
            ),
          )
        ],
      ),
    );
  }
}

效果: ani.gif