关于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 中的“正在检查