Flutter实现点击AppBar分类跳转至ListView对应索引
解决方案:用scrollable_positioned_list实现分类联动滚动
你之前遇到的列表消失问题,大概率是把ScrollablePositionedList嵌套在了SingleChildScrollView里,或是没正确配置控制器和列表参数。下面是修正后的完整实现:
步骤1:确认依赖配置
在pubspec.yaml中添加包依赖:
dependencies: scrollable_positioned_list: ^0.3.8 # 可替换为最新版本
步骤2:完整代码实现
import 'package:flutter/material.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; // 模拟你的商品分类数据结构 class ProdutoGrupo { final String dsGrupo; final List<String> produtos; ProdutoGrupo(this.dsGrupo, this.produtos); } class YourPage extends StatefulWidget { final List<ProdutoGrupo> listaProdutos; const YourPage({super.key, required this.listaProdutos}); @override State<YourPage> createState() => _YourPageState(); } class _YourPageState extends State<YourPage> { // 初始化滚动控制器 final ItemScrollController _itemScrollController = ItemScrollController(); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: PreferredSize( preferredSize: const Size.fromHeight(120), child: Column( children: [ const AppBar( title: Text('商品分类'), backgroundColor: Colors.blue, ), Expanded( child: Container( color: Colors.blue, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: widget.listaProdutos.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), child: GestureDetector( onTap: () { // 点击分类时滚动到对应索引位置 _itemScrollController.scrollTo( index: index, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(20), ), child: Center( child: Text( widget.listaProdutos[index].dsGrupo, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ), ), ), ); }, ), ), ), ], ), ), body: ScrollablePositionedList.builder( itemScrollController: _itemScrollController, itemCount: widget.listaProdutos.length, itemBuilder: (context, indexGrupo) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Card( margin: const EdgeInsets.all(8), child: Padding( padding: const EdgeInsets.all(12), child: Text( widget.listaProdutos[indexGrupo].dsGrupo, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ), // 分类下的商品列表,保持自适应高度且不独立滚动 ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: widget.listaProdutos[indexGrupo].produtos.length, itemBuilder: (context, indexProduto) { return ListTile( title: Text(widget.listaProdutos[indexGrupo].produtos[indexProduto]), ); }, ), ], ); }, ), ); } }
关键修正说明
- 移除了
body中原有的SingleChildScrollView、外层Column和Container,直接用ScrollablePositionedList.builder作为页面主滚动组件,避免嵌套可滚动组件导致的布局计算错误。 - 通过
ItemScrollController统一控制滚动逻辑,点击分类时调用scrollTo方法即可定位到对应索引的分类区域。 - 内层商品列表保留
shrinkWrap: true和NeverScrollablePhysics,确保其高度随内容自适应,且不干扰外层滚动。
原问题的常见诱因
- 将
ScrollablePositionedList嵌套在SingleChildScrollView内,导致两个可滚动组件的布局逻辑冲突。 - 未正确绑定
ItemScrollController到列表组件,或未设置正确的itemCount。
内容的提问来源于stack exchange,提问作者Roberto Henrique
相关产品推荐
相关产品推荐

