Skip to content

ListView

ListView 是最常用的滚动列表组件,用于显示可滚动的线性列表。

构造方式速查

构造方式适用场景性能
ListView()少量已知子组件一般
ListView.builder()大量数据,按需构建
ListView.separated()需要分隔符的列表
ListView.custom()自定义子组件管理最灵活

构造函数

ListView — 基本构造

dart
ListView({
  Key? key,                                              // 组件标识
  Axis scrollDirection = Axis.vertical,                   // 滚动方向:vertical=垂直,horizontal=水平
  bool reverse = false,                                  // 是否反向排列
  ScrollController? controller,                           // 滚动控制器
  bool? primary,                                          // 是否使用默认控制器(当没有 controller 时)
  ScrollPhysics? physics,                                 // 滚动物理效果
  bool shrinkWrap = false,                                // 是否根据内容确定尺寸(而非撑满父组件)
  EdgeInsetsGeometry? padding,                            // 内边距
  double? itemExtent,                                     // 固定每项高度(性能优化,避免动态计算)
  Widget? prototypeItem,                                  // 原型项(用于确定 itemExtent)
  bool addAutomaticKeepAlives = true,                     // 是否自动保持子组件存活
  bool addRepaintBoundaries = true,                       // 是否添加重绘边界
  bool addSemanticIndexes = true,                         // 是否添加语义索引
  double? cacheExtent,                                    // 预渲染区域大小
  Iterable<Widget> children = const [],                   // 子组件列表
  int? semanticChildCount,                                // 语义子组件数量
  DragStartBehavior dragStartBehavior = DragStartBehavior.start, // 拖拽开始行为
  ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, // 键盘关闭行为
  String? restorationId,                                  // 状态恢复 ID
  Clip clipBehavior = Clip.hardEdge,                      // 裁剪行为
})

ListView.builder — 按需构建(推荐大数据量)

dart
ListView.builder({
  Key? key,                                              // 组件标识
  Axis scrollDirection = Axis.vertical,                   // 滚动方向
  bool reverse = false,                                  // 是否反向排列
  ScrollController? controller,                           // 滚动控制器
  bool? primary,                                          // 是否使用默认控制器
  ScrollPhysics? physics,                                 // 滚动物理效果
  bool shrinkWrap = false,                                // 是否根据内容确定尺寸
  EdgeInsetsGeometry? padding,                            // 内边距
  double? itemExtent,                                     // 固定每项高度(性能优化)
  required IndexedWidgetBuilder itemBuilder,              // 列表项构建器(必填)
  int? itemCount,                                         // 列表项数量(null=无限)
  bool addAutomaticKeepAlives = true,                     // 是否自动保持子组件存活
  bool addRepaintBoundaries = true,                       // 是否添加重绘边界
  bool addSemanticIndexes = true,                         // 是否添加语义索引
  double? cacheExtent,                                    // 预渲染区域大小
  int? semanticChildCount,                                // 语义子组件数量
  DragStartBehavior dragStartBehavior = DragStartBehavior.start, // 拖拽开始行为
  ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, // 键盘关闭行为
  String? restorationId,                                  // 状态恢复 ID
  Clip clipBehavior = Clip.hardEdge,                      // 裁剪行为
})

ListView.separated — 带分隔符

dart
ListView.separated({
  Key? key,                                              // 组件标识
  Axis scrollDirection = Axis.vertical,                   // 滚动方向
  bool reverse = false,                                  // 是否反向排列
  ScrollController? controller,                           // 滚动控制器
  bool? primary,                                          // 是否使用默认控制器
  ScrollPhysics? physics,                                 // 滚动物理效果
  bool shrinkWrap = false,                                // 是否根据内容确定尺寸
  EdgeInsetsGeometry? padding,                            // 内边距
  required IndexedWidgetBuilder itemBuilder,              // 列表项构建器(必填)
  required IndexedWidgetBuilder separatorBuilder,         // 分隔符构建器(必填)
  int? itemCount,                                         // 列表项数量(必填)
  bool addAutomaticKeepAlives = true,                     // 是否自动保持子组件存活
  bool addRepaintBoundaries = true,                       // 是否添加重绘边界
  bool addSemanticIndexes = true,                         // 是否添加语义索引
  double? cacheExtent,                                    // 预渲染区域大小
  int? semanticChildCount,                                // 语义子组件数量
  DragStartBehavior dragStartBehavior = DragStartBehavior.start, // 拖拽开始行为
  ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, // 键盘关闭行为
  String? restorationId,                                  // 状态恢复 ID
  Clip clipBehavior = Clip.hardEdge,                      // 裁剪行为
})

常用属性速查

属性类型默认值说明
scrollDirectionAxisvertical滚动方向
reverseboolfalse是否反向排列
controllerScrollController?null滚动控制器
primarybool?null是否使用默认控制器
physicsScrollPhysics?null滚动物理效果
shrinkWrapboolfalse是否根据内容确定尺寸
paddingEdgeInsetsGeometry?null内边距
itemExtentdouble?null固定每项高度(性能优化)
itemBuilderIndexedWidgetBuilder必填列表项构建器(builder/separated)
separatorBuilderIndexedWidgetBuilder必填分隔符构建器(separated 专属)
itemCountint?null列表项数量
cacheExtentdouble?null预渲染区域大小
clipBehaviorCliphardEdge裁剪行为

physics — 滚动物理效果

效果
BouncingScrollPhysics()iOS 弹性效果
ClampingScrollPhysics()Android 夹紧效果(默认)
NeverScrollableScrollPhysics()禁止滚动
AlwaysScrollableScrollPhysics()始终可滚动

快速示例

简单列表

dart
ListView(
  children: const [
    ListTile(title: Text('第一项')),
    ListTile(title: Text('第二项')),
    ListTile(title: Text('第三项')),
  ],
)

按需构建(大数据量)

dart
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(items[index]),
    );
  },
)

带分隔符

dart
ListView.separated(
  itemCount: items.length,
  separatorBuilder: (_, __) => const Divider(height: 1),
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(items[index]),
    );
  },
)

水平滚动

dart
ListView(
  scrollDirection: Axis.horizontal,
  children: [
    Container(width: 150, color: Colors.red),
    Container(width: 150, color: Colors.blue),
    Container(width: 150, color: Colors.green),
  ],
)

常用场景

shrinkWrap — 在 Column 中嵌入 ListView

dart
Column(
  children: [
    const Text('标题'),
    ListView.builder(
      shrinkWrap: true,    // 高度包裹内容,不撑满
      physics: const NeverScrollableScrollPhysics(),  // 禁止独立滚动
      itemCount: 5,
      itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
    ),
  ],
)

shrinkWrap + 大列表

shrinkWrap: true 会一次性计算所有子组件高度,数据量大时性能差。大数据量建议在外层使用 Expanded

controller — 滚动控制

dart
final _scrollController = ScrollController();

// 滚动到底部
_scrollController.animateTo(
  _scrollController.position.maxScrollExtent,
  duration: const Duration(milliseconds: 300),
  curve: Curves.easeOut,
);

// 监听滚动
_scrollController.addListener(() {
  print('滚动位置: ${_scrollController.offset}');
});

// 判断是否滚动到底部
_scrollController.addListener(() {
  if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
    print('已到底部');
  }
});

// 记得在 dispose() 中释放
@override
void dispose() {
  _scrollController.dispose();
  super.dispose();
}

聊天列表

dart
ListView.builder(
  padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
  itemCount: messages.length,
  itemBuilder: (context, index) {
    final msg = messages[index];
    final isMe = msg.isMe;
    return Align(
      alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
      child: Container(
        margin: const EdgeInsets.only(bottom: 8),
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
        decoration: BoxDecoration(
          color: isMe ? Colors.blue : Colors.grey[300],
          borderRadius: BorderRadius.circular(12),
        ),
        child: Text(
          msg.content,
          style: TextStyle(color: isMe ? Colors.white : Colors.black87),
        ),
      ),
    );
  },
)

下拉刷新 + 上拉加载

dart
class MyListPage extends StatefulWidget {
  // ...
}

class _MyListPageState extends State<MyListPage> {
  List<String> _items = [];
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    _loadMore();
  }

  Future<void> _loadMore() async {
    setState(() => _isLoading = true);
    await Future.delayed(const Duration(seconds: 1));
    setState(() {
      _items.addAll(List.generate(10, (i) => 'Item ${_items.length + i}'));
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return RefreshIndicator(
      onRefresh: () async {
        _items.clear();
        await _loadMore();
      },
      child: ListView.builder(
        itemCount: _items.length + (_isLoading ? 1 : 0),
        itemBuilder: (context, index) {
          if (index == _items.length) {
            return const Padding(
              padding: EdgeInsets.all(16),
              child: Center(child: CircularProgressIndicator()),
            );
          }
          return ListTile(title: Text(_items[index]));
        },
      ),
    );
  }
}

基于 Flutter 官方文档整理