如何在不重建 Flutter 子项的情况下重新定位小部件?
How to reposition widget without rebuilding its children in Flutter?
在我的 Flutter 项目中,我想使用 Positioned
小部件在屏幕上重新定位列表,以便用户可以手动或使用动画移动列表。
我做的很好,但我发现,每次移动列表时,列表的每一项都会重建,这会导致一些性能问题。
这是一个基本示例:
class TestPositionedPage extends StatefulWidget {
@override
_TestPositionedPageState createState() => _TestPositionedPageState();
}
class _TestPositionedPageState extends State<TestPositionedPage> {
double _yPage = 0;
Widget _getItem(int position) {
print("get item at $position");
return ListTile(title: Text("Item at position $position"));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Align(
alignment: Alignment.topRight,
child: FlatButton(
onPressed: () {
setState(() => _yPage = Random().nextDouble() * 500);
},
child: Text("MOVE"),
color: Colors.redAccent,
),
),
Positioned(
left: 0,
top: _yPage,
child: Container(
width: 700,
height: 700,
child: ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int position) => _getItem(position),
),
),
),
],
),
),
);
}
}
在该示例中,有一个按钮,每次我单击该按钮时,它都会随机重新定位列表。但是每次重新定位列表时,这就是我在控制台中看到的内容:
I/flutter (17851): get item at 0
I/flutter (17851): get item at 1
I/flutter (17851): get item at 2
I/flutter (17851): get item at 3
I/flutter (17851): get item at 4
I/flutter (17851): get item at 5
I/flutter (17851): get item at 6
I/flutter (17851): get item at 7
I/flutter (17851): get item at 8
I/flutter (17851): get item at 9
I/flutter (17851): get item at 10
I/flutter (17851): get item at 11
I/flutter (17851): get item at 12
I/flutter (17851): get item at 13
I/flutter (17851): get item at 14
I/flutter (17851): get item at 15
I/flutter (17851): get item at 16
这意味着每次重新定位列表时,也会重建它,即使列表中没有任何更改。
所以我的问题是:有没有办法防止每次重新定位列表时重建每个项目,或有没有办法缓存列表呈现,在为了在重新定位的同时提高性能?
谢谢。
当您调用 setState(() => _yPage = Random().nextDouble() * 500);
时,整个树将再次重建,这也会导致列表重建。而是一次构建列表并重新使用。
Widget _myList;
Widget initList(){
return ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int position) => _getItem(position),
);
}
@override
void initState() {
_myList = initList();
super.initState();
}
那就这样使用列表
Positioned(
left: 0,
top: _yPage,
child: Container(
width: 700,
height: 700,
child: _myList
...
在我的 Flutter 项目中,我想使用 Positioned
小部件在屏幕上重新定位列表,以便用户可以手动或使用动画移动列表。
我做的很好,但我发现,每次移动列表时,列表的每一项都会重建,这会导致一些性能问题。
这是一个基本示例:
class TestPositionedPage extends StatefulWidget {
@override
_TestPositionedPageState createState() => _TestPositionedPageState();
}
class _TestPositionedPageState extends State<TestPositionedPage> {
double _yPage = 0;
Widget _getItem(int position) {
print("get item at $position");
return ListTile(title: Text("Item at position $position"));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Align(
alignment: Alignment.topRight,
child: FlatButton(
onPressed: () {
setState(() => _yPage = Random().nextDouble() * 500);
},
child: Text("MOVE"),
color: Colors.redAccent,
),
),
Positioned(
left: 0,
top: _yPage,
child: Container(
width: 700,
height: 700,
child: ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int position) => _getItem(position),
),
),
),
],
),
),
);
}
}
在该示例中,有一个按钮,每次我单击该按钮时,它都会随机重新定位列表。但是每次重新定位列表时,这就是我在控制台中看到的内容:
I/flutter (17851): get item at 0
I/flutter (17851): get item at 1
I/flutter (17851): get item at 2
I/flutter (17851): get item at 3
I/flutter (17851): get item at 4
I/flutter (17851): get item at 5
I/flutter (17851): get item at 6
I/flutter (17851): get item at 7
I/flutter (17851): get item at 8
I/flutter (17851): get item at 9
I/flutter (17851): get item at 10
I/flutter (17851): get item at 11
I/flutter (17851): get item at 12
I/flutter (17851): get item at 13
I/flutter (17851): get item at 14
I/flutter (17851): get item at 15
I/flutter (17851): get item at 16
这意味着每次重新定位列表时,也会重建它,即使列表中没有任何更改。
所以我的问题是:有没有办法防止每次重新定位列表时重建每个项目,或有没有办法缓存列表呈现,在为了在重新定位的同时提高性能?
谢谢。
当您调用 setState(() => _yPage = Random().nextDouble() * 500);
时,整个树将再次重建,这也会导致列表重建。而是一次构建列表并重新使用。
Widget _myList;
Widget initList(){
return ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int position) => _getItem(position),
);
}
@override
void initState() {
_myList = initList();
super.initState();
}
那就这样使用列表
Positioned(
left: 0,
top: _yPage,
child: Container(
width: 700,
height: 700,
child: _myList
...