如何在应用重新启动之间保存和恢复 Flutter ListView 的滚动位置?

Posted

技术标签:

【中文标题】如何在应用重新启动之间保存和恢复 Flutter ListView 的滚动位置?【英文标题】:How can I save and restore the scroll position of a Flutter ListView between app restarts? 【发布时间】:2020-01-14 02:35:15 【问题描述】:

我想保留 ListView 的滚动位置,以便在应用重新启动之间恢复。

所以我猜它应该使用shared_preferences 之类的东西保存在磁盘上(在 ios 上的 NSUserDefaults 和 android 上的 SharedPreferences 中)

是否有内置方式(或插件)可以做到这一点?

如果我必须手动进行,我应该何时保存滚动位置? (在原生 Android 应用程序中,我会在 onPause Activity 生命周期方法中执行此操作。)

我搜索了很多,但似乎找不到任何说明如何保存和恢复 ListView 滚动位置的帖子或示例代码。

【问题讨论】:

为什么不在 Android 中的 onSaveInstanceState 中? pub.dev/packages/shared_preferences 有什么问题? @Eugene shared_preferences 没有任何问题。我在问是否有一种内置方式(或插件)已经可以做到这一点。 【参考方案1】:

如果我必须手动执行,我应该何时保存滚动位置? (在原生 Android 应用程序中,我会在 onPause Activity 生命周期方法中执行此操作。)

您可以使用 mixin WidgetsBindingObserver 通过监听 AppLifecycleState 来检测您的应用何时进入后台以及何时进入前台

可观察的生命周期事件是:

paused — 应用程序当前对用户不可见,不响应用户输入,并且在后台运行。就像Android中的onPause() inactive — 应用程序处于非活动状态并且未接收用户输入。 (仅限 IOS) resumed — 应用程序可见并响应用户输入。就像Android中的onPostResume() suspending — 应用程序将暂时暂停。 (仅限 Android)

在示例中,我保存日期而不是滚动位置

class _TestPageState extends State<TestPage> with WidgetsBindingObserver 

  SharedPreferences prefs;

  @override
  void initState() 
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  

  @override
  void dispose() 
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) 
    print('state = $state'); // resumed, paused, inactive, suspending
    if (state == AppLifecycleState.paused) 
        prefs.setString('date', DateTime.now().toIso8601String());
    
  

  _TestPageState() 
    initPrefs();
  

  void initPrefs() async 
    prefs = await SharedPreferences.getInstance();
    print(prefs.getString('date') ?? 'no date');
  
  ...

【讨论】:

【参考方案2】:

我们现在对 Flutter 中的状态恢复提供了开箱即用的支持。 查看ScrollView 小部件内的restorationId 属性。 查看此链接以了解如何在 Flutter 中实现恢复。 https://dev.to/pedromassango/what-is-state-restoration-and-how-to-use-it-in-flutter-5blm

【讨论】:

【参考方案3】:

正如您在问题中所说 - 使用 https://pub.dev/packages/shared_preferences 是最好的选择,因为它使用了处理此类内容的本机方式 - Android 为 SharedPreferences,iOS 为 NSUserDefaults。 Android 中的新方法 PersistentBundle 也可以在颤振中使用,但没有适用于 iO 的模拟。你也可以使用各种数据库和文件存储,但在这种情况下会有点过分。

在移动设备上存储滚动状态始终是一项手动任务 - 没有开箱即用的快捷方式 - 所以只有手工制作的东西或库。

您可以将有状态小部件的整个状态存储在那里,然后将其作为一个整体恢复。

【讨论】:

以上是关于如何在应用重新启动之间保存和恢复 Flutter ListView 的滚动位置?的主要内容,如果未能解决你的问题,请参考以下文章

iPhone SDK - 如何在应用程序关闭和重新打开时保存和恢复计时器标签

应用程序重新启动 C++ Visual Studio 时保存编辑控件用户输入和恢复的有效方法

如何在程序运行之间保存/恢复表单和控件?

当用户在 10 秒内重新启动关闭的 Windows 商店应用程序时如何恢复数据

尝试热重载 Flutter 应用程序会重新启动整个应用程序

使用提供程序包 FLUTTER 关闭应用程序后保存状态