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

如何在Flutter的Screen2编辑名称并同步更新至Screen1?

Flutter 编辑页面返回后无法更新列表项名称的问题

我刚学Flutter,完成了入门教程的应用开发,已经实现列表/卡片视图切换、单词删除图标,还把无限显示改成了仅显示20个单词。现在想通过命名路由实现第二个页面:点击第一个页面的名称跳转到编辑页,修改完成后回到第一个页面能看到更新后的名称。已创建编辑页、输入框和路由,但名称更新始终不生效,特此求助,以下是我的代码:

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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Names',
      initialRoute: '/',
      routes: {
        '/': (context) => const RandomWords(),
        EditScreen.routeName: (context) => EditScreen(),
      },
    );
  }
}

class RandomWords extends StatefulWidget {
  const RandomWords({super.key});

  @override
  State<RandomWords> createState() => _RandomWordsState();
}

class _RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = <WordPair>{};
  final _biggerFont = const TextStyle(fontSize: 20);
  String selected = '';
  bool isList = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Startup Names'),
          actions: [
            IconButton(
              icon: const Icon(Icons.bookmark_border_sharp),
              onPressed: _pushSaved,
              tooltip: 'Favorites',
            ),
            IconButton(
              icon:
                  isList ? const Icon(Icons.grid_view) : const Icon(Icons.list),
              onPressed: () {
                setState(() {
                  isList = !isList;
                });
              },
              tooltip: isList ? 'Card mode' : 'List mode',
            ),
          ],
        ),
        body: isList ? lista() : cards());
  }

  Widget lista() {
    return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemCount: 40,
      itemBuilder: (context, i) {
        if (i.isOdd) return const Divider();

        final index = i ~/ 2;
        if (index >= _suggestions.length) {
          _suggestions.addAll(generateWordPairs().take(10));
        }

        return favorites(_suggestions[index], index);
      },
    );
  }

  Widget cards() {
    return GridView.builder(
        padding: const EdgeInsets.all(16.0),
        itemCount: 20,
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
            crossAxisSpacing: 5,
            mainAxisSpacing: 5,
            mainAxisExtent: 100),
        itemBuilder: (context, i) {
          if (i >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
          }

          return Card(child: favorites(_suggestions[i], i));
        });
  }

  Widget favorites(WordPair pair, int index) {
    final alreadySaved = _saved.contains(pair);
    return ListTile(
        title: Text(
          pair.asPascalCase,
          style: _biggerFont,
        ),
        trailing: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            IconButton(
              icon: Icon(alreadySaved ? Icons.favorite : Icons.favorite_border),
              color: alreadySaved ? Colors.red : null,
              tooltip: alreadySaved ? 'Remove favorite' : 'Favorite',
              onPressed: () {
                setState(() {
                  if (alreadySaved) {
                    _saved.remove(pair);
                  } else {
                    _saved.add(pair);
                  }
                });
              },
            ),
            IconButton(
              icon: const Icon(Icons.delete),
              color: Colors.black87,
              tooltip: 'Remove from list',
              onPressed: () {
                setState(() {
                  _suggestions.remove(pair);
                  _saved.remove(pair);
                });
              },
            ),
          ],
        ),
        onTap: () {
          selected = pair.asPascalCase;
          Navigator.pushNamed(context, '/second',
              arguments: Argumentos(index, selected));
        });
  }

  void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (context) {
          final tiles = _saved.map(
            (pair) {
              return ListTile(
                title: Text(
                  pair.asPascalCase,
                  style: _biggerFont,
                ),
              );
            },
          );

          final divided = tiles.isNotEmpty
              ? ListTile.divideTiles(
                  context: context,
                  tiles: tiles,
                ).toList()
              : <Widget>[];

          return Scaffold(
            appBar: AppBar(
              title: const Text('Favorites'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }
}

class EditScreen extends StatefulWidget {
  static const routeName = '/second';
  const EditScreen({super.key});

  @override
  State<EditScreen> createState() => _EditScreenState();
}

class _EditScreenState extends State<EditScreen> {
  final first = TextEditingController();
  final second = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final argumentos = ModalRoute.of(context)?.settings.arguments as Argumentos;
    String selected = argumentos.name;
    return Scaffold(
        appBar: AppBar(
          title: Text('Edit word'),
        ),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const Text("What's the new name?",
                  style: TextStyle(fontSize: 30)),
              const SizedBox(height: 30),
              Padding(
                padding:
                    const EdgeInsets.symmetric(horizontal: 100, vertical: 16),
                child: TextFormField(
                  controller: first,
                  decoration: const InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'First part of the name',
                  ),
                ),
              ),
              Padding(
                padding:
                    const EdgeInsets.symmetric(horizontal: 100, vertical: 16),
                child: TextFormField(
                  controller: second,
                  decoration: const InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Second part of the name',
                  ),
                ),
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                child: const Text('Change it'),
                onPressed: () {
                  selected = (WordPair(first.text, second.text)).toString();
                  Navigator.pushNamed(context, '/');
                },
              ),
            ],
          ),
        ));
  }
}

class Argumentos {
  final int id;
  final String name;

  Argumentos(this.id, this.name);
}

解决方案

问题核心

  1. 编辑页修改后仅更新了局部变量,未将新数据回传给主页面
  2. 使用Navigator.pushNamed返回主页面会重新创建页面实例,而非回到原页面
  3. 主页面未监听编辑页的返回结果,也未更新数据源_suggestions

修改步骤

1. 主页面接收编辑页返回的新数据

修改favorites方法中的onTap逻辑,用async/await接收返回值并更新数据源:

onTap: () async {
  final result = await Navigator.pushNamed(
    context,
    EditScreen.routeName,
    arguments: Argumentos(index, pair.asPascalCase),
  );
  if (result != null && result is WordPair) {
    setState(() {
      // 更新列表中的对应项
      _suggestions[index] = result;
      // 同步更新收藏列表(如果该单词已收藏)
      if (_saved.contains(pair)) {
        _saved.remove(pair);
        _saved.add(result);
      }
    });
  }
},

2. 编辑页携带数据返回主页面

修改编辑页按钮的onPressed逻辑,用Navigator.pop携带新创建的WordPair返回:

ElevatedButton(
  child: const Text('Change it'),
  onPressed: () {
    if (first.text.isNotEmpty && second.text.isNotEmpty) {
      final newPair = WordPair(first.text, second.text);
      Navigator.pop(context, newPair);
    }
  },
),

3. 优化编辑页初始化体验(可选)

打开编辑页时自动填充原单词的拆分内容:

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_) {
    final argumentos = ModalRoute.of(context)?.settings.arguments as Argumentos;
    final parts = argumentos.name.split(' ');
    if (parts.length == 2) {
      first.text = parts[0];
      second.text = parts[1];
    }
  });
}

4. 清理无用变量

删除主页面中未使用的String selected = '';变量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 04:01:19