PageStorageKey 的 Flutter ListView 性能问题
Flutter ListView performance issues with PageStorageKey
我有一个包含两个 ListView 的 TabBar - 每个有 250 个项目。我为每个 ListView 使用 PageStorageKey 以在视图之间切换时保留滚动位置。
如果我最初在滚动位置变化不大时在选项卡之间切换 - 比如说在列表的开头,那么在选项卡之间切换是清晰而快速的。
但是,如果我滚动到每个列表的末尾并在两个选项卡之间切换,那么在实际显示列表之前会有明显的滞后。
我可以做些什么来提高这里的性能吗?
参见:https://gist.github.com/kungfuslippers/fcae96675fb76c10f7bb5051b66ed87e
或以下代码:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
itemsA: List<String>.generate(250, (i) => "Item $i"),
itemsB: List<String>.generate(250, (i) => "Item $i")));
}
class MyApp extends StatefulWidget {
final List<String> itemsA;
final List<String> itemsB;
MyApp({Key key, @required this.itemsA, this.itemsB}) : super(key: key);
@override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
TabController _tabController;
final Key listKeyA = PageStorageKey('listA');
final Key listKeyB = PageStorageKey('listB');
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 2);
}
@override
Widget build(BuildContext context) {
final title = 'Long List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: TabBarView(controller: _tabController, children: [
ListWidget(key: listKeyA, items: widget.itemsA),
ListWidget(key: listKeyB, items: widget.itemsB),
]),
bottomNavigationBar: Container(
color: Colors.blue,
child: TabBar(
controller: _tabController,
indicatorColor: Colors.white,
tabs: <Widget>[Tab(text: "ListA"), Tab(text: "ListB")],
),
),
));
}
}
class ListWidget extends StatefulWidget {
final List<String> items;
const ListWidget({
Key key,
@required this.items,
}) : super(key: key);
@override
ListWidgetState createState() => ListWidgetState();
}
class ListWidgetState extends State<ListWidget> {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${widget.items[index]}'),
);
},
);
}
}
如果您的所有 ListView 子项都具有相同的高度,ListView 有一个名为 itemExtent 的 属性,您可以用双精度指定您的子项的高度。这将大大提高您的滚动性能。
如果您的 ListView 子项有不同的高度,那么您无能为力,但如果您在调试模式下对此进行测试,请改为在发布模式下尝试。滚动行为在调试模式下比在发布模式下更滞后。
我有一个包含两个 ListView 的 TabBar - 每个有 250 个项目。我为每个 ListView 使用 PageStorageKey 以在视图之间切换时保留滚动位置。
如果我最初在滚动位置变化不大时在选项卡之间切换 - 比如说在列表的开头,那么在选项卡之间切换是清晰而快速的。
但是,如果我滚动到每个列表的末尾并在两个选项卡之间切换,那么在实际显示列表之前会有明显的滞后。
我可以做些什么来提高这里的性能吗?
参见:https://gist.github.com/kungfuslippers/fcae96675fb76c10f7bb5051b66ed87e
或以下代码:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
itemsA: List<String>.generate(250, (i) => "Item $i"),
itemsB: List<String>.generate(250, (i) => "Item $i")));
}
class MyApp extends StatefulWidget {
final List<String> itemsA;
final List<String> itemsB;
MyApp({Key key, @required this.itemsA, this.itemsB}) : super(key: key);
@override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
TabController _tabController;
final Key listKeyA = PageStorageKey('listA');
final Key listKeyB = PageStorageKey('listB');
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 2);
}
@override
Widget build(BuildContext context) {
final title = 'Long List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: TabBarView(controller: _tabController, children: [
ListWidget(key: listKeyA, items: widget.itemsA),
ListWidget(key: listKeyB, items: widget.itemsB),
]),
bottomNavigationBar: Container(
color: Colors.blue,
child: TabBar(
controller: _tabController,
indicatorColor: Colors.white,
tabs: <Widget>[Tab(text: "ListA"), Tab(text: "ListB")],
),
),
));
}
}
class ListWidget extends StatefulWidget {
final List<String> items;
const ListWidget({
Key key,
@required this.items,
}) : super(key: key);
@override
ListWidgetState createState() => ListWidgetState();
}
class ListWidgetState extends State<ListWidget> {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${widget.items[index]}'),
);
},
);
}
}
如果您的所有 ListView 子项都具有相同的高度,ListView 有一个名为 itemExtent 的 属性,您可以用双精度指定您的子项的高度。这将大大提高您的滚动性能。
如果您的 ListView 子项有不同的高度,那么您无能为力,但如果您在调试模式下对此进行测试,请改为在发布模式下尝试。滚动行为在调试模式下比在发布模式下更滞后。