我用两个选项卡制作了一个简单的示例,每个选项卡都包含一个ListView构建器。我的目标是能够在第一个 ListView 中滚动,切换到第二个选项卡,然后切换回第一个选项卡,并从之前看到相同的滚动位置。
我曾尝试将Keys添加到每个 ListView 中,但这只是一个猜测,因为我不完全了解key。那没有帮助。
为什么ScrollControllers不保存滚动位置?
这是main.dart示例:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
ScrollController controllerA = ScrollController(keepScrollOffset: true);
ScrollController controllerB = ScrollController(keepScrollOffset: true);
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: <Widget>[
Text('controllerA'),
Text('controllerB'),
],
),
),
body: TabBarView(
children: <Widget>[
ListView.builder(
controller: controllerA,
itemCount: 2000,
itemBuilder: (context, i) {
return ListTile(
title: Text(
i.toString(),
textScaleFactor: 1.5,
style: TextStyle(color: Colors.blue),
));
}),
ListView.builder(
controller: controllerB,
itemCount: 2000,
itemBuilder: (context, i) {
return Card(
child: ListTile(
title: Text(i.toString()),
),
);
}),
],
),
),
);
}
}
这是我想要的骇人但实用的示例。但是,这感觉不像是正确的方法,因为它每帧都重建了两个 Controller 。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
double offsetA = 0.0;
double offsetB = 0.0;
@override
Widget build(BuildContext context) {
ScrollController statelessControllerA =
ScrollController(initialScrollOffset: offsetA);
statelessControllerA.addListener(() {
setState(() {
offsetA = statelessControllerA.offset;
});
});
ScrollController statelessControllerB =
ScrollController(initialScrollOffset: offsetB);
statelessControllerB.addListener(() {
setState(() {
offsetB = statelessControllerB.offset;
});
});
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: <Widget>[
Text('controllerA'),
Text('controllerB'),
],
),
),
body: TabBarView(
children: <Widget>[
ListView.builder(
controller: statelessControllerA,
itemCount: 2000,
itemBuilder: (context, i) {
return ListTile(
title: Text(
i.toString(),
textScaleFactor: 1.5,
style: TextStyle(color: Colors.blue),
));
}),
ListView.builder(
controller: statelessControllerB,
itemCount: 2000,
itemBuilder: (context, i) {
return Card(
child: ListTile(
title: Text(i.toString()),
),
);
}),
],
),
),
);
}
}
最佳答案
您可以使用AutomaticKeepAliveClientMixin
将状态保留在“选项卡 View ”中。
例如
class GetListView extends StatefulWidget{
@override
State<StatefulWidget> createState() =>_GetListViewState();
}
class _GetListViewState extends State<GetListView> with AutomaticKeepAliveClientMixin<GetListView>{
@override
Widget build(BuildContext context){
return ListView.builder(
itemCount: 2000,
itemBuilder: (context, i) {
return ListTile(
title: Text(
i.toString(),
textScaleFactor: 1.5,
style: TextStyle(color: Colors.blue),
));
});
}
@override
bool get wantKeepAlive => true;
}
不要在
ListView.builder
的子级中使用TabBarView
,而要使用GetListView
。例如
TabBarView(
children: <Widget>[
GetListView(),
ListView.builder(
controller: controllerB,
itemCount: 2000,
itemBuilder: (context, i) {
return Card(
child: ListTile(
title: Text(i.toString()),
),
);
}),
],
),
)
实现此目的的第二种方法是使用
PageStorageKey
。 Scrollable使用PageStorageKey
保存滚动偏移量。每次滚动完成时,可滚动页面的存储都会更新。例如
ListView.builder(
key: PageStorageKey<String>('controllerA'),
controller: statelessControllerA,
itemCount: 2000,
itemBuilder: (context, i) {
print("Rebuilded 1");
return ListTile(
title: Text(
i.toString(),
textScaleFactor: 1.5,
style: TextStyle(color: Colors.blue),
));
}),
注意:在第二个示例中,小部件将每次使用特定的滚动偏移量进行重建。建议使用第一个解决方案。
关于flutter - 更改选项卡时如何获取Flutter ScrollController以保存ListView.builder()的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60292911/