在Flutter中更新MaterialPageRoute的状态

时间:2018-04-04 13:02:44

标签: android ios dart flutter

我有一个小部件,它显示了一个用户列表。单击列表元素时,会创建一个新的MaterialPageRoute并将其推送到导航器,以打开显示消息历史记录的该用户的聊天屏幕。

class Users extends StatefulWidget {
  final User user;

  Users({this.user});

  @override
  UsersState createState() => new UsersState();
}

class UsersState extends State<Users> {
  Map<String, Conversation> _conversations = new Map<String, Conversation>();

  void _sendMessage(String message, String username) {
    setState(() {
      _conversations[username].messages.add(
        new Message(text: message, isFromUser: true)
      );
    });
  }

  void _openChat(String username) {
    Navigator.of(context).push(
      new MaterialPageRoute(
        builder: (context) {
          return new Chat(
            user: widget.user,
            conversation: _conversations[username],
            sendMessage: _sendMessage,
          );
        }
      )
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Column(
      children: _onlineUsers.map((username) {
        return new ListTile(
          leading: new CircleAvatar(
              child: new Text(username[0].toUpperCase())
          ),
          title: new Text(username),
          onTap: () => _openChat(username),
        );
      }).toList()
    );
  }
}

在聊天小部件中,按下发送按钮时,将调用UsersState._sendMessage,通过更新当前对话来更改状态。然后运行UsersState类的构建方法,但Chat小部件不会使用添加的消息进行更新(我猜,因为没有再次调用onTap函数)。

我试图将页面路由创建作为构建方法的直接功能,但这也不起作用。在创建状态的类中设置状态后,如何自动更新新屏幕的状态?

2 个答案:

答案 0 :(得分:1)

你想做的事情与你所拥有的有点不同;据我所知,你所拥有的是一个包含对话的小部件,然后在每次任何对话发生变化时创建新的路由。

我建议使用数据库来存储消息;在某些时候你无论如何都需要这样做。如果您只是存储在设备上,sqflite是一个很好的解决方案,而如果您希望使用FireStore将其保存到服务器可能是最简单的。

您可以拥有列出用户的主窗口小部件,但每个聊天窗口小部件本身应该是一个有状态窗口小部件,每次添加新邮件时状态都会更改。注册更改的方式取决于您使用的插件。

如果确实想在内存中只为半健壮的应用程序执行此操作,我建议您查看StreamBuilder并使用流将每封邮件发送到单个聊天或编写您自己的简单发布/订阅系统(即在创建窗口小部件时注册侦听,在窗口小部件处理时注销)。你必须传递管理注册的对象 - 我建议不要使用navigator的推送,使用pushNamed并管理Navigator / MaterialApp / WidgetApp中的东西。

虽然只是一个简单的示例(正如您在评论中所说的那样),但您可以使用InheritedWidget向下传播更改。您只需要确保InheritedWidget位于两个页面的小部件树中;如果您手动使用Navigator,则必须确保Navigator是InheritedWidget的子项,而如果您使用的是MaterialApp或WidgetsApp,则可以使用builder参数指定一个函数在MaterialApp / WidgetsApp下面但在导航器上方构建inheritedwidget。

stock app example并不是你正在做的事情,但它是一个带有列表页面和各个页面的应用程序的示例。

答案 1 :(得分:0)

有类似的情况。我的解决方案(适合您的情况):

  1. 聊天应该扩展StatefulWidget

  2. 让聊天调用setState()并将消息添加到聊天中的消息,而不是将回调传递给聊天。

  3. 由于您只是将对话的引用传递给了聊天,因此应该还会在用户中更新您的对话地图。

  4. 当导航器弹出路线时,将重建父用户,从而反映更新的对话。

  5. 如果聊天状态与父状态无关,我想你会更新聊天状态,然后调用sendMessage回调来更新父状态?这样可以避免依赖父状态变异,有些人可能会说这是一种反模式。

    到目前为止有大约2小时的颤振经验,所以我期待听到其他人是否会插话。编辑:添加第4页 - 感谢@rmtmckenzie的鸣响。