【布局 widget】Flutter ListView

简介: ListView 是最常用的滚动 widget,也是布局 widget。它在滚动方向上一个接一个地显示它的 child。

ListView 是 ScrollView 的子类,很多参数在 Fluter 滚动的基石 Scrollable 中已经讲过了,一些与 Scrollable 重合,这里只讲下 ListView 新加的参数。

itemExtent

每个 child 的高度。设置了这个参数,内部用 SliverFixedExtentList 创建 child,性能会得到提高。如果要使用这个参数的话,要求每个 child 的高度都是一样高的。即使不一样高,也会强制成一样高。

prototypeItem

如果非空,则 prototypeItem 强制子项在滚动方向上具有与给定 widget 相同的高度。内部调用 SliverPrototypeExtentList 创建 child,性能会得到提高。

itemBuilder

按需 create child。比如 Viewport 内可以显示 10 个 child,初始化完成后,ListView 就只 create 前 10 个 child(可能会再多几个,取决于 cacheExtent),滚动列表的时候,再 create 新的 child,旧的 child 会被销毁。用这种方式可以保证 ListView 的性能。

separatorBuilder

把 child 间隔开。显示的时候,每显示一个 child ,接着就会显示一个 separator。

itemCount

列表的数量。可以为空,代表数据无限。在可以给出数量的情况下,一定要给出数量。

addAutomaticKeepAlives

默认为 true,把 child 用 AutomaticKeepAlive 包起来。AutomaticKeepAlive 允许后代 widgets 控制子树是否实际保持活动状态。

if (addAutomaticKeepAlives) {
      child = AutomaticKeepAlive(child: _SelectionKeepAlive(child: child));
    }

AutomaticKeepAlive 最终用 KeepAlive 把 child 包起来。KeepAlive 将无条件地使子树保持活动状态。

 Widget build(BuildContext context) {
    return KeepAlive(
      keepAlive: _keepingAlive,
      child: _child,
    );
  }

让 KeepAlive 成为需要保留的 list child widget 子树的根 widget。 KeepAlive widget 将子树的 top render object child 标记为保持活动状态。当渲染对象滚出视图时,该列表会将子渲染对象(以及其关联的元素和状态)保存在缓存列表中,而不是销毁它们。当滚动回视图时,渲染对象将按原样重新绘制(如果在此期间未将其标记为 dirty)。

简单来说,想保持状态 addAutomaticKeepAlives 设为 true,不想保持 设为 false。

addRepaintBoundaries

默认为 true。用 RepaintBoundary 把 child 包起来。RepaintBoundary 为其子项创建一个单独的显示列表,如果子树的重绘时间与树的周围部分不同,则可以提高性能。

 if (addRepaintBoundaries) {
      child = RepaintBoundary(child: child);
 }

keyboardDismissBehavior

默认为 ScrollViewKeyboardDismissBehavior.manual。键盘不会自动收回。下面的示例修改为 ScrollViewKeyboardDismissBehavior.onDrag, 当 Listview 滑动的时候,键盘自动收起。

ListView.builder(
      itemCount: 50,
      itemBuilder: (context, index) {
        if (index == 5) {
          return const TextField();
        } else {
          return ListTile(
            title: Text('$index'),
          );
        }
      },
      keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
);

默认构造函数 ListView

 ListView({
    ...
    List<Widget> children = const <Widget>[],
  childrenDelegate = SliverChildListDelegate(
         children,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
  ),

如果列表是已知的,可以直接全部给出,适合用 默认构造函数。

ListView(
      children: List.generate(
          60,
          (index) => ListTile(
                title: Text('$index'),
              )),
    );

ListView.separated

childrenDelegate = SliverChildBuilderDelegate(
    (BuildContext context, int index) {
      final int itemIndex = index ~/ 2;
      final Widget widget;
      if (index.isEven) {
        widget = itemBuilder(context, itemIndex);
      } else {
        widget = separatorBuilder(context, itemIndex);
        assert(() {
          if (widget == null) {
            throw FlutterError('separatorBuilder cannot return null.');
          }
          return true;
        }());
      }
      return widget;
    },

ListView.separated 构造函数需要两个 builder。itemBuilder 用来 build 正文 widget,separatorBuilder 用来 build 分隔 widget

nmnxrdbc33hyk_d16932763c4a430c8ab4e65a4198a3ff.png

 ListView.separated(
      itemCount: 100,
      itemBuilder: (context, index) {
        return ListTile(title: Text('$index'));
      },
      separatorBuilder: (context, index) => const Divider(color: Colors.black,)
  
    );

ListView.builder

这是最常用的构造函数,可以让数据无限,ListView 只显示其中一部分数据。

itemCount,itemBuilder 是必须的。

ListView.builder(
      itemCount: 100,
      itemBuilder: (context, index) {
        return ListTile(
          title:Text('$index'),
        );
      },
    );

前面对参数有讲解,为了提高性能,最好能指定 itemExtent,或 prototypeItem。

ListView.custom

ListView.custom 是为了让你能自己决定 childrenDelegate。比如我们可以 选择 SliverChildListDelegate。

ListView.custom(
        childrenDelegate: SliverChildListDelegate(List.generate(
            60,
            (index) => ListTile(
                  title: Text('index'),
           ))));

这样就和默认的 ListView 构造函数一样了。
我们还可以选择 SliverChildBuilderDelegate,可以实现 ListView.builder、 ListView.separated 的功能。

相比于直接用 Scrollable, ListView 用起来挺方便的,但也是有代价的,失去了一些灵活性,后面的文章会讲。

今天就到这里了,谢谢观看。

目录
相关文章
|
3月前
|
编解码 前端开发 开发者
【Flutter前端技术开发专栏】Flutter中的响应式设计与自适应布局
【4月更文挑战第30天】Flutter框架助力移动应用实现响应式设计与自适应布局,通过层次化布局系统和`Widget`树管理,结合`BoxConstraints`定义尺寸范围,实现自适应。利用`MediaQuery`获取设备信息,调整布局以适应不同屏幕。`FractionallySizedBox`按比例设定尺寸,`LayoutBuilder`动态计算布局。借助这些工具,开发者能创建跨屏幕尺寸、方向兼容的应用,提升用户体验。
98 0
【Flutter前端技术开发专栏】Flutter中的响应式设计与自适应布局
|
3月前
|
开发框架 前端开发 数据安全/隐私保护
【Flutter 前端技术开发专栏】Flutter 中的布局与样式设计
【4月更文挑战第30天】本文探讨了Flutter的布局和样式设计,关键点包括:1) 布局基础如Column、Row和Stack用于创建复杂结构;2) Container、Center和Expanded等常用组件的作用;3) Theme和Decoration实现全局样式和组件装饰;4) 实战应用如登录界面和列表页面的构建;5) 响应式布局利用MediaQuery和弹性组件适应不同屏幕;6) 性能优化,避免过度复杂设计。了解并掌握这些,有助于开发者创建高效美观的Flutter应用。
86 0
【Flutter 前端技术开发专栏】Flutter 中的布局与样式设计
|
8天前
|
UED
Flutter之ListView实现自动滑动到底部
Flutter之ListView实现自动滑动到底部
19 1
|
1月前
|
容器
flutter 布局管理【详解】
flutter 布局管理【详解】
21 3
|
1月前
Flutter-自定义折叠流布局实现
Flutter-自定义折叠流布局实现
28 0
|
1月前
Flutter-底部弹出框(Widget层级)
文章描述了如何在Flutter中使用DraggableScrollableSheet创建一个底部弹出框,同时保持其可手势滑动关闭。作者遇到问题并提出对原控件进行扩展,以支持头部和列表布局的滑动关闭功能。
70 0
|
1月前
flutter- Row Column Expanded ListView
flutter- Row Column Expanded ListView
|
1月前
Flutter 列表学习(listview,gridview,ExpansionTile,ScrollController,RefreshIndicator)
Flutter 列表学习(listview,gridview,ExpansionTile,ScrollController,RefreshIndicator)
|
2月前
Flutter StreamBuilder 实现局部刷新 Widget
Flutter StreamBuilder 实现局部刷新 Widget
22 0
|
3月前
|
Android开发
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析