我认为在控制ListView滚动的应用中使用StatefulWidget实现以下内容是非常正常的。
//sample(a)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
MaterialApp(
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
ElevatedButton(
child: Text('Go to ListViewPage'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
ChangeNotifierProvider<ListViewPageController>(
create: (_) => ListViewPageController(),
child: ListViewPage(),
),
),
);
},
),
],
),
),
);
}
}
class ListViewPage extends StatefulWidget {
const ListViewPage({Key? key}) : super(key: key);
@override
State<ListViewPage> createState() => _ListViewPageState();
}
class _ListViewPageState extends State<ListViewPage> {
final ScrollController sc = ScrollController();
@override
void dispose() {
sc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView.builder(
controller: sc,
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(title: Text('$index'));
}),
);
}
}
另一方面,我认为也可以考虑以下使用ChangeNotifier/Provider(不是Riverpod)管理ListViewPage滚动而不使用StatefulWidget的实现。实际执行本身是没有问题的。
////sample(b)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ListViewPageController extends ChangeNotifier {
ScrollController sc = ScrollController();
}
void main() {
runApp(
MaterialApp(
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
ElevatedButton(
child: Text('Go to ListViewPage'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
ChangeNotifierProvider<ListViewPageController>(
create: (_) => ListViewPageController(),
child: ListViewPage(),
),
),
);
},
),
],
),
),
);
}
}
class ListViewPage extends StatelessWidget {
const ListViewPage({Key? key}) : super(key: key);
//↓Is this part mandatory?
/*
late final ScrollController sc = context.read<ListViewPageController>().sc;
@override
void dispose() {
sc.dispose();
super.dispose();
}
*/
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView.builder(
controller: context.read<ListViewPageController>().sc,
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(title: Text('$index'));
}),
);
}
}
问题1示例(B)与示例(a)具有相同的行为,但由于ListViewPage是StatelessWidget,因此不会调用sc.dispose。
我目前的理解是,当我们从ListViewPage返回到HomePage时,ListViewPageController将被销毁,但ScrollController也会自动销毁吗?难道我不应该自己写关于sc.dispose的代码吗?
或者我必须让ListViewPage成为一个StatefulWidget,然后自己编写代码来调用state.dispose中的sc.dispose?
Question 2最近,我听到了下面的说法(解释)。
ChangeNtifier(或StateNotfier)的子类不应依赖于任何UI代码。Flutter的ScrollController/PageController/TextEditingController/Forms等是Flutter SDK中的类(即UI代码)。所以在这个例子中ListViewPageController不应该有(依赖于)ScrollController。“
是这样吗?
我还看到了另一个使用Scrollable.ensureVisible来控制滚动的示例代码,但是由于这个Scrollable类也是UI代码,所以在ChangeNotifier子类中使用它是不是一个不好的做法,如下所示?(在这种情况下,每个ListTile都应该有一个GlobalKey。
就我个人而言,我认为如果ChangeNotifier子类包含ScrollController、PageController等,会更容易理解。在Flutter中开发时,这个理论有多重要?
class ListViewPageController extends ChangeNotifier {
ScrollController sc = ScrollController();
scrollRequest(int scrollIndex) {
Scrollable.ensureVisible(keyList[scrollIndex - 100].currentContext!,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
alignment: 0.5,
alignmentPolicy: ScrollPositionAlignmentPolicy.explicit);
}
}
2条答案
按热度按时间bihw5rsg1#
在样本B中,sc是< ScrollController >另一个obj中的一个obj< ListViewPageController >,假设它是lc。
当lc(disposed)->被删除时,sc(disposed)->被删除。
Q2.在ListViewPageController中按住ScrollController可能会在ListViewPage仍处于活动状态时意外释放ListViewPageController时导致错误。
如果你想访问ScrollController,尝试将其注入ListViewPageController将是一个更好的做法。
svdrlsy42#
你也可以在ListViewPageController中调用dispose方法,并在那里dispose ScrollController sc,我也使用这种方法,但我不确定它是否正确。