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

如何实现Flutter ListView、GridView指定索引/行的展开收起功能

实现方案

核心思路

  • 定义bool类型的展开状态变量,标记当前是否展示全部内容
  • 动态计算列表的itemCount:未展开时用限制的展示数量,展开后用总数量
  • 列表下方拼接可点击的箭头图标,点击时切换状态触发UI刷新

GridView 场景代码示例

import 'package:flutter/material.dart';

class ExpandableGridView extends StatefulWidget {
  const ExpandableGridView({super.key});

  @override
  State<ExpandableGridView> createState() => _ExpandableGridViewState();
}

class _ExpandableGridViewState extends State<ExpandableGridView> {
  // 展开状态标记
  bool _isExpanded = false;
  // 按钮数组,这里模拟25个元素
  final List<Widget> buttons = List.generate(25, (index) => Container(color: Colors.blueAccent, child: Center(child: Text('$index', style: TextStyle(color: Colors.white)))));
  // 交叉轴数量
  final int crossAxisCount = 5;
  // 初始展示行数
  final int initRows = 3;

  @override
  Widget build(BuildContext context) {
    // 计算实际展示的item数量
    final showItemCount = _isExpanded ? buttons.length : initRows * crossAxisCount;
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: crossAxisCount,
            crossAxisSpacing: 2,
            mainAxisSpacing: 2,
            childAspectRatio: 1.825,
          ),
          padding: const EdgeInsets.all(0),
          physics: const NeverScrollableScrollPhysics(),
          scrollDirection: Axis.vertical,
          shrinkWrap: true,
          itemCount: showItemCount,
          itemBuilder: (context, index) {
            return buttons[index];
          },
        ),
        // 点击切换展开/收起状态的箭头
        IconButton(
          onPressed: () {
            setState(() {
              _isExpanded = !_isExpanded;
            });
          },
          icon: Icon(_isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down),
        )
      ],
    );
  }
}

ListView 场景代码示例

import 'package:flutter/material.dart';

class ExpandableListView extends StatefulWidget {
  const ExpandableListView({super.key});

  @override
  State<ExpandableListView> createState() => _ExpandableListViewState();
}

class _ExpandableListViewState extends State<ExpandableListView> {
  bool _isExpanded = false;
  // 初始展示的列表项数量
  final int initShowCount = 5;
  // 列表项数组,模拟10个元素
  final List<Widget> listItems = List.generate(10, (index) => ListTile(title: Text('列表项 $index')));

  @override
  Widget build(BuildContext context) {
    final showItemCount = _isExpanded ? listItems.length : initShowCount;
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        ListView.builder(
          physics: const NeverScrollableScrollPhysics(),
          shrinkWrap: true,
          itemCount: showItemCount,
          itemBuilder: (context, index) {
            return listItems[index];
          },
        ),
        IconButton(
          onPressed: () => setState(() => _isExpanded = !_isExpanded),
          icon: Icon(_isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down),
        )
      ],
    );
  }
}

扩展说明

  • 如果需要添加展开收起的过渡动画,可以给箭头图标套AnimatedSwitcher实现图标切换动画,列表高度变化也可以配合AnimatedContainer实现平滑过渡
  • 若列表项高度不固定,可以提前计算未展开时的最大高度限制,结合LimitedBox配合展开状态控制展示范围

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 23:06:04