Flutter中点击SliverAppBar按钮实现SliverList动态最小化
解决方案
核心思路
- 状态提升:将列表最小化的状态放在父组件
_MyHomePageState中统一管理,解决跨组件状态同步问题 - 动画实现:通过
TweenAnimationBuilder实现列表项高度、透明度的平滑过渡效果 - 事件透传:将最小化按钮的点击事件回调到父组件修改状态
完整修改代码
1. 修改主类代码
class _MyHomePageState extends State<MyHomePage> { // 控制列表是否最小化的状态 bool _isListMinimized = false; // 切换最小化状态的方法 void _toggleMinimizeList() { setState(() { _isListMinimized = !_isListMinimized; }); } @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ CustomTitleAppbar( title: 'Sliver List', // 传入点击回调 onMinimizeTap: _toggleMinimizeList, ), // 传入最小化状态给列表组件 CustomSliverListView(isMinimized: _isListMinimized), ], ), ); } }
2. 修改SliverAppBar组件代码
class CustomTitleAppbar extends StatefulWidget { const CustomTitleAppbar({ Key? key, required this.title, // 新增点击回调参数 required this.onMinimizeTap, }) : super(key: key); final String title; final VoidCallback onMinimizeTap; @override _CustomTitleAppbarState createState() => _CustomTitleAppbarState(); } class _CustomTitleAppbarState extends State<CustomTitleAppbar> { @override Widget build(BuildContext context) { return SliverAppBar( title: Text(widget.title), pinned: true, snap: false, backgroundColor: Colors.lightGreen, actions: [ IconButton( onPressed: () { // 调用父组件传入的回调 widget.onMinimizeTap(); }, icon: const Icon(Icons.minimize_rounded), ), ], ); } }
3. 修改SliverList组件代码
class CustomSliverListView extends StatelessWidget { const CustomSliverListView({ Key? key, // 新增最小化状态参数 required this.isMinimized, }) : super(key: key); final bool isMinimized; @override Widget build(BuildContext context) { return SliverList( delegate: SliverChildListDelegate( List.generate(5, (index) => TweenAnimationBuilder<double>( // 动画时长300毫秒,可自行调整 duration: const Duration(milliseconds: 300), // 动画曲线,平滑效果 curve: Curves.easeInOut, tween: Tween<double>( // 正常状态下列表项高度,默认ListTile高度约为70 begin: 70, // 最小化状态下高度为0,完全隐藏 end: isMinimized ? 0 : 70, ), builder: (context, height, child) { return SizedBox( height: height, // 配合透明度动画让过渡更自然 child: Opacity( opacity: height / 70, child: child, ), ); }, child: ListTile( leading: CircleAvatar( child: Text('${index + 1}'), backgroundColor: Colors.lightGreen, foregroundColor: Colors.white, ), title: Text('Row ${index + 1}'), subtitle: Text('Subtitle ${index + 1}'), trailing: const Icon(Icons.star_border_outlined), ), )), ), ); } }
自定义调整说明
- 如果不需要完全隐藏,只需要缩小列表项,可以把
end: isMinimized ? 0 : 70里的0改成你想要的最小高度,比如30,同时可以调整子组件的显示样式,比如最小化时隐藏副标题 - 动画时长可以修改
Duration(milliseconds: 300)里的数值调整快慢 - 动画效果可以修改
curve参数,比如Curves.fastOutSlowIn等实现不同的动效
内容的提问来源于stack exchange,提问作者Mudasir Habib
相关产品推荐
相关产品推荐

