关于flutter列表的性能优化,你必须要了解的
这里是坚果前端小课堂,大家喜欢的话,可以关注我的公众号“坚果前端,”,或者加我好友,获取更多精彩内容
嵌套列表 - 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 {@overrideWidget 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;@overridevoid 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(),),);}}@overrideWidget 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);@overrideState createState() => ColorRowState(); }class ColorRowState extends State<ColorRow> {Color? color;@overridevoid initState() {super.initState();color = randomColor();}@overrideWidget 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”的实例打印到控制台,
更糟糕的是,一旦向下滚动大约一百行,就会再生成一百行。😱😱😱
而且你滑动的快的时候列表会抖动!
重新构建嵌套列表
要了解如何使您的用户免受卡顿威胁,请等待我的第二节,下一节将使用 Slivers 而不是 ListViews 重建相同的 UI。
使用 Slivers 的列表列表
下面的代码构建了与之前相同的 UI,但这次它使用Slivers 而不是收缩包装ListView对象。本页的其余部分将引导您逐步完成更改。
如何将嵌套列表迁移到 Slivers
第1步
首先,将最外面的 ListView 更改为SliverList.
// Before @override Widget build(BuildContext context) {return ListView.builder(itemCount: numberOfLists,itemBuilder: (context, index) => innerLists[index],); }变成:
// After @override Widget build(BuildContext context) {return CustomScrollView(slivers: innerLists); }第2步
其次,将内部列表的类型从List<ListView>更改为 List<SliverList>。
// Before List<ListView> innerLists = [];变成:
// After List<SliverList> innerLists = [];第 3 步
现在是时候重建内部列表了。的SliverList类是比原始略有不同ListView的类,与主要差异是的外观delegate。
原始版本ListView对所有内容都使用对象,不知道内部构建器构造函数将被shrinkWrap.
// Before @override void initState() {super.initState();for (int i = 0; i < numberOfLists; 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(),),);} }更改后,ListView对象被替换为SliverList对象,每个对象都使用一个SliverChildBuilderDelegate来提供高效的按需构建。
// After @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(SliverList(delegate: SliverChildBuilderDelegate((BuildContext context, int index) => _innerList[index],childCount: numberOfItemsPerList,),),);} }完整代码:
import 'package:flutter/material.dart'; import 'dart:math' as math;void main() {runApp(SliversApp()); }class SliversApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(debugShowCheckedModeBanner: false,title: 'ShrinkWrap vs Slivers',home: Scaffold(appBar: AppBar(title: const Text("Revenge of the Slivers"),),body: const ShrinkWrapSlivers(),),);} }class ShrinkWrapSlivers extends StatefulWidget {const ShrinkWrapSlivers({Key? key,}) : super(key: key);@override_ShrinkWrapSliversState createState() => _ShrinkWrapSliversState(); }class _ShrinkWrapSliversState extends State<ShrinkWrapSlivers> {List<SliverList> innerLists = [];final numLists = 15;final numberOfItemsPerList = 100;@overridevoid 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(SliverList(delegate: SliverChildBuilderDelegate((BuildContext context, int index) => _innerList[index],childCount: numberOfItemsPerList,),),);}}@overrideWidget build(BuildContext context) {return CustomScrollView(slivers: innerLists);} }@immutable class ColorRow extends StatefulWidget {const ColorRow({Key? key}) : super(key: key);@overrideState createState() => ColorRowState(); }class ColorRowState extends State<ColorRow> {Color? color;@overridevoid initState() {super.initState();color = randomColor();}@overrideWidget 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);Lazy building!
上面的代码已经应用了这些更改。运行应用程序并注意 Flutter 不再需要立即渲染 100 个 ColorRow 小部件。当您滚动时,会动态构建更多小部件,正如您所期望的那样。更好的是,一直滚动到下一个列表也不会产生任何特殊费用。
Flutter 会根据需要重新构建小部件,而且很快。
这节课对你来说怎么样,可以的话,支持一下吧
你快速的滑动的时候会发现,这个时候的列表没有抖动!
总结
以上是生活随笔为你收集整理的关于flutter列表的性能优化,你必须要了解的的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 找不到 tools.jar。请检查 C:
- 下一篇: 如何修复 Flutter 中的“正在检查