You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

页面导航时保持状态:如何持久化第二页的地点选择列表状态?

如何持久化第二页的列表选择状态?

这是个很常见的Flutter页面状态丢失问题,本质是因为你从第二页pop回第一页时,第二页的Widget实例被销毁了,再次push时会重新创建,所以之前的选择状态就没了。下面给你几种不同场景下的解决方案,你可以根据自己的需求选择:

方案一:用AutomaticKeepAliveClientMixin保持页面状态

这是Flutter自带的状态保持方案,适合页面只是被push/pop、没有被彻底移除路由栈的场景。

你只需要让第二页的State类混入AutomaticKeepAliveClientMixin,并实现wantKeepAlive返回true,同时在build方法里调用super.build(context):

class SecondPage extends StatefulWidget {
  final List<String> initialSelected; // 接收第一页传来的已选地点
  const SecondPage({Key? key, required this.initialSelected}) : super(key: key);

  @override
  State<SecondPage> createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> with AutomaticKeepAliveClientMixin {
  late List<String> _selectedLocations;

  @override
  void initState() {
    super.initState();
    _selectedLocations = List.from(widget.initialSelected);
  }

  // 开启状态保持
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    // 必须调用super.build,否则状态保持不生效
    super.build(context);
    return Scaffold(
      appBar: AppBar(title: const Text('选择地点')),
      body: ListView(
        children: [
          for (final location in ['北京', '上海', '广州', '深圳'])
            CheckboxListTile(
              title: Text(location),
              value: _selectedLocations.contains(location),
              onChanged: (value) {
                setState(() {
                  value == true 
                      ? _selectedLocations.add(location) 
                      : _selectedLocations.remove(location);
                });
              },
            ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Navigator.pop(context, _selectedLocations),
        child: const Icon(Icons.save),
      ),
    );
  }
}

注意:如果你的路由操作是pushReplacement或者页面被从路由栈中移除,这个方案就不生效了。

方案二:全局状态管理(以Riverpod为例)

如果你的应用比较复杂,或者多个页面需要共享这个选择状态,全局状态管理是更合适的方案。它会把状态保存在独立于Widget树的容器里,不管页面怎么重建,状态都不会丢失。

首先定义一个状态Provider:

final selectedLocationsProvider = StateProvider<List<String>>((ref) => []);

第一页读取并展示状态:

class FirstPage extends ConsumerWidget {
  const FirstPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedLocations = ref.watch(selectedLocationsProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('首页')),
      body: Wrap(
        children: selectedLocations.map((loc) => Chip(label: Text(loc))).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Navigator.push(
          context,
          MaterialPageRoute(builder: (_) => const SecondPage()),
        ),
        child: const Icon(Icons.add),
      ),
    );
  }
}

第二页修改全局状态:

class SecondPage extends ConsumerWidget {
  const SecondPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedLocations = ref.watch(selectedLocationsProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('选择地点')),
      body: ListView(
        children: [
          for (final location in ['北京', '上海', '广州', '深圳'])
            CheckboxListTile(
              title: Text(location),
              value: selectedLocations.contains(location),
              onChanged: (value) {
                ref.read(selectedLocationsProvider.notifier).update((state) {
                  final newList = List.from(state);
                  value == true 
                      ? newList.add(location) 
                      : newList.remove(location);
                  return newList;
                });
              },
            ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Navigator.pop(context),
        child: const Icon(Icons.save),
      ),
    );
  }
}

方案三:在第一页保存状态,跳转时传递

这是最基础的方案,适合只有两个页面交互的简单场景,不需要额外依赖。

第一页保存已选状态,跳转时把当前状态传递给第二页,等待返回后更新状态:

class FirstPage extends StatefulWidget {
  const FirstPage({Key? key}) : super(key: key);

  @override
  State<FirstPage> createState() => _FirstPageState();
}

class _FirstPageState extends State<FirstPage> {
  List<String> _selectedLocations = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('首页')),
      body: Wrap(
        children: _selectedLocations.map((loc) => Chip(label: Text(loc))).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final result = await Navigator.push<List<String>>(
            context,
            MaterialPageRoute(
              builder: (_) => SecondPage(initialSelected: _selectedLocations),
            ),
          );
          if (result != null) {
            setState(() => _selectedLocations = result);
          }
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

第二页接收初始状态并修改,返回时把新状态带回第一页:

class SecondPage extends StatefulWidget {
  final List<String> initialSelected;
  const SecondPage({Key? key, required this.initialSelected}) : super(key: key);

  @override
  State<SecondPage> createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
  late List<String> _currentSelected;

  @override
  void initState() {
    super.initState();
    _currentSelected = List.from(widget.initialSelected);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('选择地点')),
      body: ListView(
        children: [
          for (final location in ['北京', '上海', '广州', '深圳'])
            CheckboxListTile(
              title: Text(location),
              value: _currentSelected.contains(location),
              onChanged: (value) {
                setState(() {
                  value == true 
                      ? _currentSelected.add(location) 
                      : _currentSelected.remove(location);
                });
              },
            ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Navigator.pop(context, _currentSelected),
        child: const Icon(Icons.save),
      ),
    );
  }
}

方案四:本地持久化(以SharedPreferences为例)

如果需要即使重启APP也能保留选择状态,就需要把状态保存到本地存储。这里用SharedPreferences做示例,你也可以用Hive、SQLite等更强大的存储方案。

首先添加依赖到pubspec.yaml:

dependencies:
  shared_preferences: ^2.2.2

第二页加载并保存本地状态:

class SecondPage extends StatefulWidget {
  const SecondPage({Key? key}) : super(key: key);

  @override
  State<SecondPage> createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
  late List<String> _selectedLocations;
  final _prefs = SharedPreferences.getInstance();

  @override
  void initState() {
    super.initState();
    _loadSavedLocations();
  }

  Future<void> _loadSavedLocations() async {
    final prefs = await _prefs;
    setState(() {
      _selectedLocations = prefs.getStringList('selected_locations') ?? [];
    });
  }

  Future<void> _saveAndReturn() async {
    final prefs = await _prefs;
    await prefs.setStringList('selected_locations', _selectedLocations);
    Navigator.pop(context, _selectedLocations);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('选择地点')),
      body: ListView(
        children: [
          for (final location in ['北京', '上海', '广州', '深圳'])
            CheckboxListTile(
              title: Text(location),
              value: _selectedLocations.contains(location),
              onChanged: (value) {
                setState(() {
                  value == true 
                      ? _selectedLocations.add(location) 
                      : _selectedLocations.remove(location);
                });
              },
            ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _saveAndReturn,
        child: const Icon(Icons.save),
      ),
    );
  }
}

第一页也可以从本地加载初始状态:

class FirstPage extends StatefulWidget {
  const FirstPage({Key? key}) : super(key: key);

  @override
  State<FirstPage> createState() => _FirstPageState();
}

class _FirstPageState extends State<FirstPage> {
  late List<String> _selectedLocations;
  final _prefs = SharedPreferences.getInstance();

  @override
  void initState() {
    super.initState();
    _loadSavedLocations();
  }

  Future<void> _loadSavedLocations() async {
    final prefs = await _prefs;
    setState(() {
      _selectedLocations = prefs.getStringList('selected_locations') ?? [];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('首页')),
      body: Wrap(
        children: _selectedLocations.map((loc) => Chip(label: Text(loc))).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final result = await Navigator.push<List<String>>(
            context,
            MaterialPageRoute(builder: (_) => const SecondPage()),
          );
          if (result != null) {
            setState(() => _selectedLocations = result);
          }
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

总结选择建议

  • 简单页面跳转保持状态:选方案一;
  • 多页面共享状态:选方案二;
  • 仅两个页面交互:选方案三;
  • 需要持久化到本地(重启APP不丢失):选方案四。

内容的提问来源于stack exchange,提问作者David De Jesus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:42:10