You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:如何为PreferredSizeWidget(AppBar)添加伸缩与淡入淡出动画?

实现SliverAppBar Bottom的淡入淡出+滑动动画

要解决SliverAppBar底部区域切换生硬的问题,核心是把Bottom区域封装在动画组件中,同时满足PreferredSizeWidget的布局要求,具体实现如下:

1. 初始化动画控制器与动画对象

在页面的State类中创建动画控制器,同时定义控制透明度和偏移量的动画:

late AnimationController _controller;
late Animation<double> _opacityAnim;
late Animation<double> _offsetAnim;
bool _isBottomVisible = false;

@override
void initState() {
  super.initState();
  _controller = AnimationController(
    duration: const Duration(milliseconds: 300),
    vsync: this,
  );
  // 透明度动画:0→1(淡入)/1→0(淡出)
  _opacityAnim = Tween<double>(begin: 0, end: 1).animate(
    CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
  );
  // Y轴偏移动画:-20→0(下滑显示)/0→-20(上滑隐藏)
  _offsetAnim = Tween<double>(begin: -20, end: 0).animate(
    CurvedAnimation(parent: _controller, curve: Curves.easeOut),
  );
}

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

2. 自定义带动画的Bottom组件

创建继承自PreferredSizeWidget的组件,把动画逻辑封装进去,直接适配SliverAppBar的bottom属性:

class AnimatedBottomBar extends StatelessWidget implements PreferredSizeWidget {
  final Animation<double> opacityAnim;
  final Animation<double> offsetAnim;
  final Widget child;

  const AnimatedBottomBar({
    super.key,
    required this.opacityAnim,
    required this.offsetAnim,
    required this.child,
  });

  @override
  Size get preferredSize => const Size.fromHeight(48); // 自定义底部栏高度

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: Tween<Offset>(
        begin: Offset(0, offsetAnim.value / preferredSize.height),
        end: const Offset(0, 0),
      ).animate(opacityAnim),
      child: FadeTransition(
        opacity: opacityAnim,
        child: child,
      ),
    );
  }
}

3. 绑定SliverAppBar与点击事件

在SliverAppBar中使用自定义动画组件,通过按钮点击触发动画切换:

SliverAppBar(
  title: const Text("带动画的SliverAppBar"),
  actions: [
    IconButton(
      icon: Icon(_isBottomVisible ? Icons.expand_less : Icons.expand_more),
      onPressed: () async {
        if (_isBottomVisible) {
          // 执行淡出上移动画
          await _controller.reverse();
        } else {
          // 执行淡入下移动画
          await _controller.forward();
        }
        setState(() {
          _isBottomVisible = !_isBottomVisible;
        });
      },
    ),
  ],
  bottom: _isBottomVisible
      ? AnimatedBottomBar(
          opacityAnim: _opacityAnim,
          offsetAnim: _offsetAnim,
          child: Container(
            height: 48,
            color: Colors.blue[100],
            alignment: Alignment.center,
            child: const Text("动画显示的底部区域"),
          ),
        )
      : null,
  pinned: true,
)

关键说明

  • 动画组合:通过SlideTransition控制上下滑动、FadeTransition控制透明度,完美模拟fadeInDown/fadeOutUp效果
  • 布局兼容:自定义组件实现preferredSize,确保SliverAppBar能正确计算整体高度
  • 状态同步:先播放动画再切换显示状态,避免出现生硬的突然切换

内容的提问来源于stack exchange,提问作者Lazizbek Fayziev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 18:55:22