【布局 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 用起来挺方便的,但也是有代价的,失去了一些灵活性,后面的文章会讲。

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

目录
相关文章
|
27天前
|
缓存 监控 前端开发
优化 Flutter 应用启动速度的策略,涵盖理解启动过程、资源加载优化、减少初始化工作、界面布局优化、异步初始化、预加载关键数据、性能监控与分析等方面
本文探讨了优化 Flutter 应用启动速度的策略,涵盖理解启动过程、资源加载优化、减少初始化工作、界面布局优化、异步初始化、预加载关键数据、性能监控与分析等方面,并通过案例分析展示了具体措施和效果,强调了持续优化的重要性及未来优化方向。
54 10
|
2天前
|
存储 容器
Flutter 构建自适应布局
Flutter 构建自适应布局
Flutter 构建自适应布局
|
2天前
|
容器
Flutter Widget 解析
Flutter Widget 解析
|
26天前
|
开发框架 数据安全/隐私保护 开发者
Flutter 是一款强大的跨平台移动应用开发框架,本文深入探讨了其布局与样式设计
Flutter 是一款强大的跨平台移动应用开发框架,本文深入探讨了其布局与样式设计,涵盖布局基础、常用组件、样式设计、实战应用、响应式布局及性能优化等方面,助力开发者打造精美用户界面。
41 7
|
2天前
|
存储 容器
Flutter 有状态Widget 和 无状态Widget
Flutter 有状态Widget 和 无状态Widget
|
1月前
深入理解Flutter鸿蒙next版本 中的Widget继承:使用extends获取数据与父类约束
本文详细介绍了Flutter中如何通过继承其他Widget来创建自定义组件。首先解释了Widget继承的基本概念,包括StatelessWidget和StatefulWidget的区别。接着通过具体示例展示了如何继承StatelessWidget和StatefulWidget,并在子类中访问父类的build方法和状态。最后,结合多个自定义Widget展示了如何在实际应用中灵活使用继承和组合来构建复杂的UI。
76 8
|
1月前
|
开发者 容器
Flutter&鸿蒙next 布局架构原理详解
本文详细介绍了 Flutter 中的主要布局方式,包括 Row、Column、Stack、Container、ListView 和 GridView 等布局组件的架构原理及使用场景。通过了解这些布局 Widget 的基本概念、关键属性和布局原理,开发者可以更高效地构建复杂的用户界面。此外,文章还提供了布局优化技巧,帮助提升应用性能。
103 4
|
1月前
|
容器
flutter&鸿蒙next 使用 InheritedWidget 实现跨 Widget 传递状态
在 Flutter 中,状态管理至关重要。本文详细介绍了如何使用 InheritedWidget 实现跨 Widget 的状态传递。InheritedWidget 允许数据在 Widget 树中向下传递,适用于多层嵌套的场景。通过一个简单的计数器示例,展示了如何创建和使用 InheritedWidget,包括其基础概念、工作原理及代码实现。虽然 InheritedWidget 较底层,但它是许多高级状态管理解决方案的基础。
103 2
|
1月前
|
容器
深入理解 Flutter 鸿蒙版的 Stack 布局:适配屏幕与层叠样式布局
Flutter 的 Stack 布局组件允许你将多个子组件层叠在一起,实现复杂的界面效果。本文介绍了 Stack 的基本用法、核心概念(如子组件层叠、Positioned 组件和对齐属性),以及如何使用 MediaQuery 和 LayoutBuilder 实现响应式设计。通过示例展示了照片展示与文字描述、动态调整层叠布局等高级用法,帮助你构建更加精美和实用的 Flutter 应用。
137 2
|
2月前
|
容器
Flutter&鸿蒙next 布局架构原理详解
Flutter&鸿蒙next 布局架构原理详解