Flutter 动画之 Implicit 隐式动画

Flutter 动画之 Implicit 隐式动画

  • Implicit 隐式动画指的是通过修改组件的属性自动触发平滑过渡效果的动画实现方式(状态驱动),和显式动画(需要通过 AnimationController 手动控制)不同,隐式动画通过封装底层动画逻辑实现,无需手动控制管理动画
  • 隐式动画需要指定动画的开始和结束状态,以及动画的持续时间等参数
  • 隐式动画开发效率较高,但灵活性较低(依赖预设属性和默认动画)
  • 动画一旦开始,只能从初始状态到目标状态,无法循环或反向播放
  • 通过嵌套多个隐式动画组件可实现复合效果(比如同时调整位置和透明度)
dart 复制代码
//系统内置的隐式动画(以 Animated 开头的组件,都继承自 ImplicitlyAnimatedWidget)
//动画触发依赖于属性变化
//AnimatedContainer:动态改变容器属性(比如宽高、颜色和对齐方式等)
//AnimatedDefaultTextStyle:控制文本样式过渡
//AnimatedSlide​:控制滑动
//AnimatedScale​:控制缩放
//AnimatedRotation​:控制旋转
//AnimatedOpacity​​:控制透明度渐变
//AnimatedPositioned​​:在 Stack 中平滑移动子组件(必须配合 Stack 使用)
//AnimatedSwitcher:组件切换时添加过渡动画(比如淡入淡出)

//AnimatedIcon:图标动画
//AnimatedTheme:主题切换时的平滑过渡
//AnimatedPadding:动态控制边距
//AnimatedAlign:动态调整子组件对齐方式

AnimatedContainer

dart 复制代码
class MyAnimatedContainer extends StatefulWidget {
  const MyAnimatedContainer({super.key});

  @override
  State<MyAnimatedContainer> createState() => _MyAnimatedContainerState();
}

class _MyAnimatedContainerState extends State<MyAnimatedContainer> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() => _flag = !_flag),
        child: const Icon(Icons.animation),
      ),
      body: Center(
        child: AnimatedContainer(
            duration: const Duration(milliseconds: 500),
            width: _flag ? 100 : 200,
            height: _flag ? 100 : 200,
            color: _flag ? Colors.blue : Colors.red,
            alignment: _flag ? Alignment.topLeft : Alignment.bottomRight,
            child: const Text('test AnimatedContainer', textDirection: TextDirection.rtl)),
      ),
    );
  }
}

AnimatedDefaultTextStyle

dart 复制代码
class MyAnimatedDefaultTextStyle extends StatefulWidget {
  const MyAnimatedDefaultTextStyle({super.key});

  @override
  State<MyAnimatedDefaultTextStyle> createState() =>
      _MyAnimatedDefaultTextStyleState();
}

class _MyAnimatedDefaultTextStyleState
    extends State<MyAnimatedDefaultTextStyle> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => setState(() => _flag = !_flag),
          child: const Icon(Icons.animation),
        ),
        body: Center(
            child: AnimatedDefaultTextStyle(
          style: _flag
              ? const TextStyle(fontSize: 24)
              : const TextStyle(fontSize: 16),
          duration: const Duration(milliseconds: 500),
          child: const Text('test AnimatedDefaultTextStyle'),
        )));
  }
}

AnimatedSlide

dart 复制代码
class MyAnimatedSlide extends StatefulWidget {
  const MyAnimatedSlide({super.key});

  @override
  State<MyAnimatedSlide> createState() => _MyAnimatedSlideState();
}

class _MyAnimatedSlideState extends State<MyAnimatedSlide> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => setState(() => _flag = !_flag),
          child: const Icon(Icons.animation),
        ),
        body: Center(
            child: AnimatedSlide(
                offset: _flag ? const Offset(1.0, 0.0) : const Offset(0.0, 0.0),
                duration: const Duration(milliseconds: 500),
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                  child: const Center(
                    child: Text('test AnimatedSlide'),
                  ),
                ))));
  }
}

AnimatedScale

dart 复制代码
class MyAnimatedScale extends StatefulWidget {
  const MyAnimatedScale({super.key});

  @override
  State<MyAnimatedScale> createState() => _MyAnimatedScaleState();
}

class _MyAnimatedScaleState extends State<MyAnimatedScale> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => setState(() => _flag = !_flag),
          child: const Icon(Icons.animation),
        ),
        body: Center(
            child: AnimatedScale(
          scale: _flag ? 3.0 : 1.5,
          duration: const Duration(milliseconds: 500),
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
            child: const Center(
              child: Text('test AnimatedScale'),
            ),
          ),
        )));
  }
}

AnimatedRotation

dart 复制代码
class MyAnimatedRotation extends StatefulWidget {
  const MyAnimatedRotation({super.key});

  @override
  State<MyAnimatedRotation> createState() => _MyAnimatedRotationState();
}

class _MyAnimatedRotationState extends State<MyAnimatedRotation> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => setState(() => _flag = !_flag),
          child: const Icon(Icons.animation),
        ),
        body: Center(
            child: AnimatedRotation(
          turns: _flag ? 1 : 0, //旋转的圈数
          duration: const Duration(seconds: 1),
          child: const Icon(
            Icons.refresh,
            size: 200,
            color: Colors.blue,
          ),
        )));
  }
}

AnimatedOpacity​​

dart 复制代码
class MyAnimatedOpacity extends StatefulWidget {
  const MyAnimatedOpacity({super.key});

  @override
  State<MyAnimatedOpacity> createState() => _MyAnimatedOpacityState();
}

class _MyAnimatedOpacityState extends State<MyAnimatedOpacity> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => setState(() => _flag = !_flag),
          child: const Icon(Icons.animation),
        ),
        body: Center(
            child: AnimatedOpacity(
          opacity: _flag ? 1.0 : 0.2,
          duration: const Duration(milliseconds: 500),
          child: const Text('test AnimatedOpacity​​ Fade In/Out'),
        )));
  }
}

AnimatedPositioned

dart 复制代码
class MyAnimatedPositioned extends StatefulWidget {
  const MyAnimatedPositioned({super.key});

  @override
  State<MyAnimatedPositioned> createState() => _MyAnimatedPositionedState();
}

class _MyAnimatedPositionedState extends State<MyAnimatedPositioned> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => setState(() => _flag = !_flag),
          child: const Icon(Icons.animation),
        ),
        body: Center(
          child: Stack(
            children: [
              const Positioned(
                top: 100,
                left: 100,
                child: Text('固定位置文本', style: TextStyle(fontSize: 20)),
              ),
              AnimatedPositioned(
                duration: const Duration(milliseconds: 500),
                top: _flag ? 100 : 300,
                left: _flag ? 100 : 300,
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
              ),
              const Positioned(
                top: 300,
                left: 300,
                child: Text('固定位置文本222', style: TextStyle(fontSize: 20)),
              ),
            ],
          ),
        ));
  }
}

AnimatedSwitcher

dart 复制代码
class MyAnimatedSwitcher extends StatefulWidget {
  const MyAnimatedSwitcher({super.key});

  @override
  State<MyAnimatedSwitcher> createState() => _MyAnimatedSwitcherState();
}

class _MyAnimatedSwitcherState extends State<MyAnimatedSwitcher> {
  int _flag = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => setState(() => _flag++),
          child: const Icon(Icons.animation),
        ),
        body: Center(
          child: AnimatedSwitcher(
            duration: const Duration(milliseconds: 500),
            transitionBuilder: (Widget child, Animation<double> animation) {
              return FadeTransition(
                //淡入淡出
                opacity: animation,
                child: ScaleTransition(
                  //缩放
                  scale: animation,
                  child: child,
                ),
              );
            },
            child: Text(
              'test AnimatedSwitcher $_flag',
              //key: UniqueKey(), //生成唯一 key
              key: ValueKey(_flag), //必须设置唯一 key
            ),
          ),
        ));
  }
}

TweenAnimationBuilder 补间动画构建器

  • TweenAnimationBuilder 继承自 ImplicitlyAnimatedWidget
  • 侧重使用 Tween 来定义动画,允许自定义任意类型的补间动画,比系统内置的隐式动画要灵活
  • 支持复杂动画逻辑(比如颜色渐变、路径动画和多属性同步动画等)
dart 复制代码
class MyTweenAnimationBuilder extends StatefulWidget {
  const MyTweenAnimationBuilder({super.key});

  @override
  State<MyTweenAnimationBuilder> createState() => _MyTweenAnimationBuilderState();
}

class _MyTweenAnimationBuilderState extends State<MyTweenAnimationBuilder> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => setState(() => _flag = !_flag),
          child: const Icon(Icons.animation),
        ),
        body: Center(
          child: TweenAnimationBuilder<double>(
            tween: Tween<double>(begin: 10, end: 20),
            duration: const Duration(seconds: 5),
            builder: (context, value, child) {
              return Text("test TweenAnimationBuilder ${value.toInt()}",
                  style: TextStyle(fontSize: value));
            },
          ),
        ));
  }
}

自定义隐式动画

  • 直接继承 ImplicitlyAnimatedWidget
  • ImplicitlyAnimatedWidget 内部对 AnimationController 进行了封装,无需手动控制动画控制器
dart 复制代码
class MyImplicitlyAnimatedWidget extends StatefulWidget {
  const MyImplicitlyAnimatedWidget({super.key});

  @override
  State<MyImplicitlyAnimatedWidget> createState() =>
      _MyImplicitlyAnimatedWidgetState();
}

class _MyImplicitlyAnimatedWidgetState
    extends State<MyImplicitlyAnimatedWidget> {
  double _width = 100;
  double _height = 100;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() {
          _width = _width > 40 ? 40 : 100;
          _height = _height > 40 ? 40 : 100;
        }),
        child: const Icon(Icons.animation),
      ),
      body: Center(
          child: CustomImplicitlyAnimatedWidget(
        width: _width,
        height: _height,
        duration: const Duration(seconds: 1),
      )),
    );
  }
}

//自定义 ImplicitlyAnimatedWidget
class CustomImplicitlyAnimatedWidget extends ImplicitlyAnimatedWidget {
  const CustomImplicitlyAnimatedWidget(
      {super.key,
      required super.duration,
      required this.width,
      required this.height});

  final double width;
  final double height;

  @override
  AnimatedWidgetBaseState<CustomImplicitlyAnimatedWidget> createState() =>
      _CustomAnimatedWidgetBaseState();
}

//AnimatedWidgetBaseState 继承自 ImplicitlyAnimatedWidgetState
class _CustomAnimatedWidgetBaseState
    extends AnimatedWidgetBaseState<CustomImplicitlyAnimatedWidget> {
  Tween<double>? _widthTween;
  Tween<double>? _heightTween;

  @override
  void forEachTween(TweenVisitor<dynamic> visitor) {
    //visitor 的 tween 代表当前的 tween,第一次调用为 null
    //初始化每一个可变化属性的 tween
    //更新每一个可变化属性的 tween
    //可同时管理多个属性,定义属性初始值及变化逻辑
    _widthTween = visitor(_widthTween, widget.width, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;

    _heightTween = visitor(_heightTween, widget.height, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: _widthTween!.evaluate(animation),
      height: _heightTween!.evaluate(animation),
      color: Colors.blue,
    );
  }
}
相关推荐
bst@微胖子2 小时前
Flutter之路由和导航
flutter
亚洲小炫风3 小时前
flutter 中各种日志
前端·flutter·日志·log
勤劳打代码7 小时前
游刃有余 —— Isolate 轻量化实战
flutter·github·dart
RichardLai8811 小时前
[Flutter 基础] - Flutter基础组件 - Text
android·flutter
Ya-Jun21 小时前
常用第三方库精讲:cached_network_image图片加载优化
android·flutter
WDeLiang1 天前
Flutter 环境搭建
flutter·ios·visual studio code
程一个大前端1 天前
【Flutter高效开发】GetX指南:一文学会状态管理、路由与依赖注入
flutter
DEVIL1 天前
Flutter中各类Controller的本质
android·flutter
ak啊1 天前
Flutter UI 组件应用一:布局、交互、动画与弹窗
flutter