这里是坚果前端小课堂,大家喜欢的话,可以关注我的公众号“坚果前端,”,或者加我好友,获取更多精彩内容

嵌套列表 - ShrinkWrap 与 Slivers

使用 ShrinkWrap 的列表列表

下面是一些使用​​ListView​​对象呈现列表列表的代码,内部列表的​​shrinkWrap​​值设置为 true。​​shrinkWrap​​强行评估整个内部列表,允许它请求有限的高度,而不是通常的​​ListView​​对象高度,即无穷大!

下面是基本的代码结构:

ListView(
// Setting `shrinkWrap` to `true` here is both unnecessary and expensive.
children: <Widget>[
ListView.builder(
itemCount: list1Children.length,
itemBuilder: (BuildContext context, int index) {
return list1Children[index];
},
// This forces the `ListView` to build all of its children up front,
// negating much of the benefit of using `ListView.builder`.
shrinkWrap: true,
),
ListView.builder(
itemCount: list2Children.length,
itemBuilder: (BuildContext context, int index) {
return list2Children[index];
},
// This forces the `ListView` to build all of its children up front,
// negating much of the benefit of using `ListView.builder`.
shrinkWrap: true,
),
...
],
)

注意:观察外部​​ListView​​没有将其​​shrinkWrap​​ 值设置为​​true​​。只有内部列表需要设置​​shrinkWrap​​。

另请注意:虽然​​ListView.builder​​(默认情况下)有效地构建其子项,为您节省构建屏幕外小部件的不必要成本,但设置 ​​shrinkWrap​​为​​true​​覆盖此默认行为!

import 'package:flutter/material.dart';
import 'dart:math' as math;

void main() {
runApp(ShrinkWrApp());
}

class ShrinkWrApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ShrinkWrap vs Slivers',
home: Scaffold(
appBar: AppBar(
title: const Text("ShrinkWrap, Street Rat, I don't, Buy that!"),
),
body: const ShrinkWrapSlivers(),
),
);
}
}

class ShrinkWrapSlivers extends StatefulWidget {
const ShrinkWrapSlivers({
Key? key,
}) : super(key: key);

@override
_ShrinkWrapSliversState createState() => _ShrinkWrapSliversState();
}

class _ShrinkWrapSliversState extends State<ShrinkWrapSlivers> {
List<ListView> innerLists = [];
final numLists = 15;
final numberOfItemsPerList = 100;

@override
void initState() {
super.initState();
for (int i = 0; i < numLists; i++) {
final _innerList = <ColorRow>[];
for (int j = 0; j < numberOfItemsPerList; j++) {
_innerList.add(const ColorRow());
}
innerLists.add(
ListView.builder(
itemCount: numberOfItemsPerList,
itemBuilder: (BuildContext context, int index) => _innerList[index],
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
),
);
}
}

@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: numLists,
itemBuilder: (context, index) => innerLists[index]);
}
}

@immutable
class ColorRow extends StatefulWidget {
const ColorRow({Key? key}) : super(key: key);

@override
State createState() => ColorRowState();
}

class ColorRowState extends State<ColorRow> {
Color? color;

@override
void initState() {
super.initState();
color = randomColor();
}

@override
Widget build(BuildContext context) {
print('Building ColorRowState');
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
randomColor(),
randomColor(),
],
),
),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(height: 50, width: 50, color: Colors.white),
),
Flexible(
child: Column(
children: const <Widget>[
Padding(
padding: EdgeInsets.all(8),
child: Text('这里是 坚果前端小课堂!',
style: TextStyle(color: Colors.white)),
),
],
),
),
],
),
);
}
}

Color randomColor() =>
Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);

一切都建立起来!

当您滚动浏览此 UI 并注意该​​ColorBarState.build​​方法的调用方式时,会出现可怕的部分 。每个内部列表包含 100 个元素,因此当 UI 加载时,您会立即看到 100 个“Building ColorBarState”的实例打印到控制台,

更糟糕的是,一旦向下滚动大约一百行,就会再生成一百行。😱😱😱

flutter 中的列表的性能优化前奏#yyds干货盘点# _flutter

而且你滑动的快的时候列表会抖动!

重新构建嵌套列表

要了解如何使您的用户免受卡顿威胁,请等待我的第二节,下一节将使用 Slivers 而不是 ListViews 重建相同的 UI。