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

如何跨类复用非静态列表,实现双页面列表同步自动更新?

嘿,这个问题其实是Flutter里很常见的「状态共享」需求——要让两个页面共用同一份数据,改一处全同步对吧?我给你几个实用的方案,从简单到进阶都有,你可以根据项目规模选~

核心思路先理清楚

你现在的问题在于列表数据是绑定在单个页面的State里的,每个页面都有自己的独立数据副本,自然没法同步。解决的关键是:

  • 把列表数据抽离成全局唯一的可监听对象
  • 两个页面都依赖这个对象,当数据变化时自动触发UI更新

方案1:用ValueNotifier(轻量无依赖,适合小项目)

这个方案不用额外装包,Flutter自带,适合简单的列表场景。

第一步:创建全局的可监听列表

在项目里新建一个单独的文件(比如shared_data.dart),定义一个全局的ValueNotifier:

import 'package:flutter/foundation.dart';

// 全局唯一的列表数据,初始为空
final itemListNotifier = ValueNotifier<List<String>>([]);

第二步:修改ListView页面的代码

原来的增删逻辑改成操作这个全局的itemListNotifier,并用ValueListenableBuilder监听数据变化:

import 'package:flutter/material.dart';
import 'shared_data.dart';

class ListViewPage extends StatelessWidget {
  const ListViewPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ListView 页面'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pushNamed(context, '/stackCards'),
            child: const Text('去堆叠卡片页'),
          ),
        ],
      ),
      // 用ValueListenableBuilder监听数据变化,自动重建列表
      body: ValueListenableBuilder<List<String>>(
        valueListenable: itemListNotifier,
        builder: (context, items, child) {
          return ListView.builder(
            itemCount: items.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(items[index]),
                trailing: IconButton(
                  icon: const Icon(Icons.delete),
                  onPressed: () {
                    // 修改数据时要创建新列表,不能直接修改原列表(ValueNotifier只监听引用变化)
                    itemListNotifier.value = List.from(items)..removeAt(index);
                  },
                ),
              );
            },
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 添加新元素,同样要创建新列表
          final newItems = List.from(itemListNotifier.value);
          newItems.add('新元素 ${newItems.length + 1}');
          itemListNotifier.value = newItems;
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

第三步:修改StackCard.builder页面的代码

同样用ValueListenableBuilder监听数据,构建堆叠卡片:

import 'package:flutter/material.dart';
import 'shared_data.dart';

class StackCardPage extends StatelessWidget {
  const StackCardPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('堆叠卡片页面'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('返回'),
          ),
        ],
      ),
      body: ValueListenableBuilder<List<String>>(
        valueListenable: itemListNotifier,
        builder: (context, items, child) {
          if (items.isEmpty) {
            return const Center(child: Text('暂无元素'));
          }
          // 用Stack和Positioned实现堆叠效果
          return Stack(
            children: List.generate(items.length, (index) {
              return Positioned(
                top: index * 25.0,
                left: index * 25.0,
                right: index * 25.0,
                child: Card(
                  elevation: 6,
                  color: Colors.grey[100]!.withOpacity(0.9),
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          items[index],
                          style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
                        ),
                        Align(
                          alignment: Alignment.centerRight,
                          child: IconButton(
                            icon: const Icon(Icons.delete, color: Colors.red),
                            onPressed: () {
                              itemListNotifier.value = List.from(items)..removeAt(index);
                            },
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              );
            }),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          final newItems = List.from(itemListNotifier.value);
          newItems.add('堆叠新元素 ${newItems.length + 1}');
          itemListNotifier.value = newItems;
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

方案2:用Provider(进阶推荐,适合中大型项目)

如果你的项目后续会有更多状态共享需求,Provider是Flutter生态里最常用的状态管理库之一,结构更清晰。

第一步:添加依赖

在pubspec.yaml里添加Provider:

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.5  # 版本号以最新为准

然后执行flutter pub get。

第二步:创建数据模型类

新建item_list_model.dart,定义一个继承ChangeNotifier的模型,封装列表和增删方法:

import 'package:flutter/foundation.dart';

class ItemListModel extends ChangeNotifier {
  // 私有列表,外部只能通过getter访问
  final List<String> _items = [];

  // 对外暴露只读的列表
  List<String> get items => _items;

  // 添加元素,修改后通知监听者
  void addItem(String item) {
    _items.add(item);
    notifyListeners();
  }

  // 删除元素,修改后通知监听者
  void removeItem(int index) {
    _items.removeAt(index);
    notifyListeners();
  }
}

第三步:在应用顶层注入模型

修改main.dart,用ChangeNotifierProvider把模型注入到整个应用:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'list_view_page.dart';
import 'stack_card_page.dart';
import 'item_list_model.dart';

void main() {
  runApp(
    // 全局提供ItemListModel的实例
    ChangeNotifierProvider(
      create: (context) => ItemListModel(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '共享列表Demo',
      initialRoute: '/',
      routes: {
        '/': (context) => const ListViewPage(),
        '/stackCards': (context) => const StackCardPage(),
      },
    );
  }
}

第四步:修改两个页面的代码

ListView页面:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'item_list_model.dart';

class ListViewPage extends StatelessWidget {
  const ListViewPage({super.key});

  @override
  Widget build(BuildContext context) {
    // 获取全局的ItemListModel实例
    final itemList = Provider.of<ItemListModel>(context);

    return Scaffold(
      appBar: AppBar(
        title: const Text('ListView 页面'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pushNamed(context, '/stackCards'),
            child: const Text('去堆叠卡片页'),
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: itemList.items.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(itemList.items[index]),
            trailing: IconButton(
              icon: const Icon(Icons.delete),
              onPressed: () => itemList.removeItem(index),
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          itemList.addItem('新元素 ${itemList.items.length + 1}');
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}
StackCard页面:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'item_list_model.dart';

class StackCardPage extends StatelessWidget {
  const StackCardPage({super.key});

  @override
  Widget build(BuildContext context) {
    final itemList = Provider.of<ItemListModel>(context);

    return Scaffold(
      appBar: AppBar(
        title: const Text('堆叠卡片页面'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('返回'),
          ),
        ],
      ),
      body: itemList.items.isEmpty
          ? const Center(child: Text('暂无元素'))
          : Stack(
              children: List.generate(itemList.items.length, (index) {
                return Positioned(
                  top: index * 25.0,
                  left: index * 25.0,
                  right: index * 25.0,
                  child: Card(
                    elevation: 6,
                    color: Colors.grey[100]!.withOpacity(0.9),
                    child: Padding(
                      padding: const EdgeInsets.all(16.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            itemList.items[index],
                            style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
                          ),
                          Align(
                            alignment: Alignment.centerRight,
                            child: IconButton(
                              icon: const Icon(Icons.delete, color: Colors.red),
                              onPressed: () => itemList.removeItem(index),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                );
              }),
            ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          itemList.addItem('堆叠新元素 ${itemList.items.length + 1}');
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

两种方案的区别

  • ValueNotifier:轻量、无依赖,适合小项目或简单的状态共享场景,但全局变量的方式在大型项目里可能不易维护。
  • Provider:结构清晰,适合中大型项目,支持更复杂的状态逻辑,后续扩展更方便。

不管选哪种,核心都是让两个页面依赖同一份可监听的数据,这样修改数据时,所有监听的UI都会自动同步更新~

内容的提问来源于stack exchange,提问作者Nico

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:17:32