在 ScrollController
中使用
ListView
作为 StatelessWidget
是否ok?如果是的话,控制器该如何处置?
如果您使用
ScrollController
,我认为您的小部件中可能有一个状态(要更改或维护)。
在这种情况下,您需要去
StatefulWidget
。
我只需更改为
StatefulWidget
并使用 dispose()
方法来清理内存。
但首先,想想你的控制器是否有存在的目的。也许在你的情况下是有道理的。
也检查这个答案 --> 无状态小部件会自行处理吗?
可以在无状态小部件中拥有此功能。为了保持我们的小部件无状态,我们使用 ControllerProvider。这是一个仅保存控制器的 Provider 类。它不会通知听众。这是 Provider 类:
class ControllerProvider {
final List<ChangeNotifier> _controllers = [];
T getController<T extends ChangeNotifier>({
required T Function() create,
}) {
final controller = create();
_controllers.add(controller);
return controller;
}
void disposeAll() {
for (var controller in _controllers) {
print('${controller.toString()} disposed');
controller.dispose();
}
_controllers.clear();
}
}
在无状态小部件中,我们有以下方法:
Widget _buildView(BuildContext context) {
final controllerProvider = context.read<ControllerProvider>();
_scrollController = controllerProvider.getController<ScrollController>(
create: () => ScrollController(),
);
print('ScrollController ${_scrollController.toString()} created');
_scrollController.addListener(() { // other code });
// other code to return the widget UI
在我们的 Widget 构建方法中,我们将小部件包装在一个简单的 Provider 中,如下所示:
Widget build(BuildContext context) {
return ChangeNotifierProvider<SomeUIProvider>(
create: (_) => SomeUIProvider()
..initializeProvider(errorCallback: (String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}),
child: Provider<ControllerProvider>(
create: (_) => ControllerProvider(),
dispose: (_, controllerProvider) => controllerProvider.disposeAll(),
child: Builder(builder: (context) => _buildView(context)),
),
);
}
每当我们需要使用像 TextEditingController 和 ScrollController 实例这样的控制器时,我们将小部件包装在这个 Provider 中,定义它的 dispose 方法。当此小部件离开导航堆栈或从导航堆栈中弹出时,由 ControllerProvider 管理的所有控制器都将被释放。