Flutter的Widget学习(三)

引言

本文将详细介绍以下 6 个核心动画组件 和一个常用的 UI 组件:

AnimatedOpacity:透明度动画
AnimatedPhysicalModel:物理模型(阴影、圆角等)动画
AnimatedPositioned:用于 Stack 中元素的定位动画
AnimatedSize:尺寸自适应动画
AnimatedWidget:自定义动画构建基类
AppBar:应用顶部导航栏

1. AnimatedOpacity:透明度动画组件

用途:

AnimatedOpacity 用于在 opacity 值变化时自动执行淡入淡出动画。

示例代码:

class AnimatedOpacityDemo extends StatefulWidget {
  @override
  _AnimatedOpacityDemoState createState() => _AnimatedOpacityDemoState();
}

class _AnimatedOpacityDemoState extends State<AnimatedOpacityDemo> {
  double _opacity = 1.0;

  void _toggleOpacity() {
    setState(() {
      _opacity = _opacity == 1.0 ? 0.2 : 1.0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("AnimatedOpacity")),
      body: Center(
        child: AnimatedOpacity(
          opacity: _opacity,
          duration: Duration(seconds: 1),
          curve: Curves.easeInOut,
          child: Container(
            width: 200,
            height: 200,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text(
              "Fade In/Out",
              style: TextStyle(color: Colors.white, fontSize: 18),
            ),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _toggleOpacity,
        child: Icon(Icons.visibility),
      ),
    );
  }
}

参数说明:

opacity 透明度值(0.0 完全透明,1.0 完全不透明)
duration 动画持续时间
curve 动画曲线(如 Curves.ease, Curves.bounceOut)

使用场景:

  • 图片加载占位符淡入
  • 按钮禁用状态视觉提示
  • 消息提示自动隐藏

AnimatedPhysicalModel:物理外观动画组件

用途:

AnimatedPhysicalModel 可以动画化地改变组件的物理外观,如阴影、圆角、边框、海拔(elevation)等。

示例代码:

class AnimatedPhysicalModelDemo extends StatefulWidget {
  @override
  _AnimatedPhysicalModelDemoState createState() =>
      _AnimatedPhysicalModelDemoState();
}

class _AnimatedPhysicalModelDemoState extends State<AnimatedPhysicalModelDemo> {
  bool _elevated = false;

  void _toggleElevation() {
    setState(() {
      _elevated = !_elevated;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("AnimatedPhysicalModel")),
      body: Center(
        child: AnimatedPhysicalModel(
          duration: Duration(milliseconds: 300),
          curve: Curves.easeInOut,
          elevation: _elevated ? 20 : 0,
          color: Colors.white,
          shadowColor: Colors.black,
          borderRadius: BorderRadius.circular(_elevated ? 20 : 0),
          child: Container(
            width: 200,
            height: 200,
            color: Colors.purple,
            alignment: Alignment.center,
            child: Text(
              "Elevated",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _toggleElevation,
        child: Icon(Icons.change_circle),
      ),
    );
  }
}

参数说明:

elevation 海拔高度(影响阴影)
color / shadowColor 背景色和阴影颜色
borderRadius 圆角半径
shape 形状(矩形、圆形)

使用场景:

  • 卡片点击高亮效果
  • 明暗模式切换时的 UI 变化
  • 悬浮按钮动态提升

3. AnimatedPositioned:Stack 中的定位动画

用途:

AnimatedPositionedPositioned 的动画版本,用于在 Stack 中对子组件进行带动画的定位。

示例代码:

class AnimatedPositionedDemo extends StatefulWidget {
  @override
  _AnimatedPositionedDemoState createState() => _AnimatedPositionedDemoState();
}

class _AnimatedPositionedDemoState extends State<AnimatedPositionedDemo> {
  bool _move = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("AnimatedPositioned")),
      body: Stack(
        children: [
          AnimatedPositioned(
            duration: Duration(seconds: 1),
            curve: Curves.elasticOut,
            top: _move ? 300 : 100,
            left: _move ? 200 : 50,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.orange,
              alignment: Alignment.center,
              child: Text("Move", style: TextStyle(color: Colors.white)),
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _move = !_move;
          });
        },
        child: Icon(Icons.directions_run),
      ),
    );
  }
}

参数说明:

top / left / right / bottom 相对位置
width / height 尺寸(也可动画)
duration 动画持续时间
curve 动画曲线

使用场景:

  • 拖拽元素回弹动画
  • 引导页元素移动
  • 游戏角色移动动画

4. AnimatedSize:自动尺寸动画

用途:

AnimatedSize 会在其子组件尺寸发生变化时,自动执行尺寸过渡动画。

示例代码:

class AnimatedSizeDemo extends StatefulWidget {
  @override
  _AnimatedSizeDemoState createState() => _AnimatedSizeDemoState();
}

class _AnimatedSizeDemoState extends State<AnimatedSizeDemo>
    with TickerProviderStateMixin {
  bool _expanded = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("AnimatedSize")),
      body: Center(
        child: AnimatedSize(
          duration: Duration(milliseconds: 300),
          curve: Curves.fastOutSlowIn,
          child: Container(
            width: _expanded ? 300 : 100,
            height: _expanded ? 300 : 100,
            color: Colors.teal,
            padding: EdgeInsets.all(16),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text("Tap to Expand", style: TextStyle(color: Colors.white)),
                if (_expanded)
                  Text("Expanded Content", style: TextStyle(color: Colors.white)),
              ],
            ),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _expanded = !_expanded;
          });
        },
        child: Icon(Icons.expand),
      ),
    );
  }
}

参数说明:

duration 动画持续时间
curve 动画曲线
alignment 对齐方式
child 子组件(尺寸变化会触发动画)

使用场景:

  • 折叠/展开面板
  • 动态内容区域尺寸变化
  • 加载更多内容时的平滑扩展

5. AnimatedWidget:自定义动画组件基类

用途:
AnimatedWidget 是一个抽象类,用于创建依赖于 Listenable(通常是 Animation)的可重用动画组件。

示例代码:自定义旋转图标

class RotatingIcon extends AnimatedWidget {
  final IconData icon;
  final double size;

  const RotatingIcon({
    Key? key,
    required Animation<double> animation,
    this.icon = Icons.refresh,
    this.size = 24,
  }) : super(key: key, listenable: animation);

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable as Animation<double>;
    return Transform.rotate(
      angle: animation.value * 2 * pi,
      child: Icon(icon, size: size),
    );
  }
}

// 使用示例
class AnimatedWidgetDemo extends StatefulWidget {
  @override
  _AnimatedWidgetDemoState createState() => _AnimatedWidgetDemoState();
}

class _AnimatedWidgetDemoState extends State<AnimatedWidgetDemo>
    with TickerProviderStateMixin {
  late AnimationController _controller;

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

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("AnimatedWidget")),
      body: Center(
        child: RotatingIcon(
          animation: _controller,
          icon: Icons.sync,
          size: 50,
        ),
      ),
    );
  }
}

优势:

  • 将动画逻辑封装成可复用组件
  • 自动监听动画变化并重建 UI
  • 提高代码复用性和可维护性

使用场景:

  • 自定义加载动画
  • 可复用的动效图标
  • 复杂动画组件封装

6. AppBar:应用顶部导航栏

用途:

AppBar 是 Material Design 风格的应用顶部导航栏,通常作为 Scaffold 的一部分使用。

示例代码:

class AppBarDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("AppBar 示例"),
        leading: IconButton(
          icon: Icon(Icons.menu),
          onPressed: () {
            Scaffold.of(context).openDrawer();
          },
        ),
        actions: [
          IconButton(
            icon: Icon(Icons.search),
            onPressed: () {},
          ),
          IconButton(
            icon: Icon(Icons.more_vert),
            onPressed: () {},
          ),
        ],
        backgroundColor: Colors.blue,
        elevation: 4,
        centerTitle: true,
        bottom: PreferredSize(
          preferredSize: Size.fromHeight(48),
          child: Container(
            height: 48,
            alignment: Alignment.center,
            child: Text("标签页"),
          ),
        ),
      ),
      body: Center(child: Text("页面内容")),
    );
  }
}

核心参数说明:

title 标题文本或组件
leading 左侧按钮(如菜单、返回)
actions 右侧操作按钮列表
backgroundColor 背景色
elevation 阴影高度
centerTitle 标题是否居中
bottom 底部附加组件(如 TabBar)
flexibleSpace 背景空间(用于背景图片等)

使用场景:

  • 页面标题展示
  • 导航控制(返回、菜单)
  • 搜索、设置等操作入口
  • Tab 切换导航

最佳实践建议

  • 使用 AnimatedOpacity 实现淡入淡出效果,简单高效。
  • 使用 AnimatedPhysicalModel 创建具有物理反馈的 UI 元素。
  • 使用 AnimatedPositioned 实现 Stack 内元素的平滑移动。
  • 使用 AnimatedSize 实现内容区域的平滑展开/收起。
  • 使用 AnimatedWidget 封装复杂或可复用的动画逻辑。
  • 使用 AppBar 标准化应用导航,提升用户体验一致性。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容