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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:15:27