Flutter如何实现滚动向下隐藏顶部卡片、滚动向上显示?
Hey there! 作为Flutter新手碰到这个滚动交互的需求太常见啦,我来给你一步步拆解怎么实现这个效果~
实现滚动时隐藏/显示顶部筛选卡片的方案
核心思路
我们可以通过ScrollController监听滚动事件,判断滚动方向(向上/向下),再结合动画组件让筛选卡片的显示状态平滑切换,避免生硬的跳变。
完整代码示例
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('滚动隐藏筛选卡片示例')), body: const ScrollHideDemo(), ), ); } } class ScrollHideDemo extends StatefulWidget { const ScrollHideDemo({super.key}); @override State<ScrollHideDemo> createState() => _ScrollHideDemoState(); } class _ScrollHideDemoState extends State<ScrollHideDemo> { // 滚动控制器,用来监听滚动偏移 final ScrollController _scrollController = ScrollController(); // 筛选卡片的高度,默认完全显示 double _filterCardHeight = 80.0; // 记录上一次的滚动位置,用来判断滚动方向 double _previousScrollOffset = 0.0; @override void initState() { super.initState(); // 给滚动控制器添加监听事件 _scrollController.addListener(_handleScroll); } void _handleScroll() { final currentOffset = _scrollController.offset; // 向下滚动:当前偏移 > 上一次偏移,且已经滚动过顶部 if (currentOffset > _previousScrollOffset && currentOffset > 0) { setState(() { _filterCardHeight = 0.0; // 隐藏卡片 }); } else { setState(() { _filterCardHeight = 80.0; // 显示卡片 }); } // 更新上一次的滚动位置 _previousScrollOffset = currentOffset; } @override void dispose() { // 销毁控制器,避免内存泄漏 _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: [ // 用AnimatedContainer实现平滑过渡动画 AnimatedContainer( duration: const Duration(milliseconds: 300), height: _filterCardHeight, child: Card( margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: const Center( child: Text('筛选卡片:地区 | 价格 | 类型'), ), ), ), // 可滚动的列表内容 Expanded( child: ListView.builder( controller: _scrollController, itemCount: 50, itemBuilder: (context, index) { return ListTile( title: Text('列表项 $index'), subtitle: const Text('这里是列表的具体内容'), ); }, ), ), ], ); } }
关键代码说明
- ScrollController:核心用来捕捉滚动的偏移量,通过对比当前偏移和上一次偏移,判断用户是向上还是向下滚动。
- AnimatedContainer:代替普通Container,在高度变化时自动生成300毫秒的平滑过渡动画,让隐藏/显示的过程更自然。
- dispose方法:一定要记得在组件销毁时释放ScrollController,防止内存泄漏。
进阶优化小技巧
如果觉得改变高度的效果不够丝滑,也可以用Transform.translate控制卡片的垂直偏移,比如向下滚动时让卡片向上移出屏幕,向上滚动时再滑回来:
// 替换原有的AnimatedContainer部分 AnimatedContainer( duration: const Duration(milliseconds: 300), transform: Matrix4.translationValues(0, _filterCardOffset, 0), child: Card( // 卡片内容保持不变 margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: const Center( child: Text('筛选卡片:地区 | 价格 | 类型'), ), ), ) // 同时修改_handleScroll逻辑: double _filterCardOffset = 0.0; // 替换原来的_height变量 void _handleScroll() { final currentOffset = _scrollController.offset; if (currentOffset > _previousScrollOffset && currentOffset > 0) { setState(() { _filterCardOffset = -80.0; // 向上偏移隐藏 }); } else { setState(() { _filterCardOffset = 0.0; // 回到原位显示 }); } _previousScrollOffset = currentOffset; }
这样的交互会更贴近常见的App体验,你可以根据自己的UI风格选择合适的实现方式~
内容的提问来源于stack exchange,提问作者user21043019
相关产品推荐
相关产品推荐

