【问题标题】:How to call into a flutter widget's state from the widget如何从小部件调用颤振小部件的状态
【发布时间】:2019-11-29 05:10:59
【问题描述】:

我是 dart/flutter 的新手,在理解沟通模式方面有点困难。

一个反复出现的问题是,我一直希望在小部件上公开一个公共方法,以便其他小部件可以调用它。

问题在于有状态的小部件。在这些情况下,我需要调用小部件状态来完成实际工作。

问题是小部件没有状态副本。 我一直在小部件中保存状态的副本,但这当然会引发警告,因为它会使小部件可变。

让我举一个具体的例子:

我有一个专门的菜单,它可以有一组菜单项。 每个都是有状态的。

当菜单关闭时,它需要遍历它拥有的菜单项列表并告诉每个菜单项隐藏(菜单项在菜单中不可见,因此隐藏菜单不起作用)。

所以菜单有如下代码:

class Menu{
  closeMenu() {
    for (var menuItem in menuItems) {
      menuItem.close();
    }
  }

这样可以正常工作,但当然在 MenuItem 类中我需要:

class MenuItem {
  MenuItemState state;

  close()
  {
    state.close();
  }

当然,将状态对象存储在 MenuItem 中是一个问题,因为 MenuItem 是不可变的。 (这只是一个警告,因此代码可以正常工作,但它显然不是预期的设计模式)。

【问题讨论】:

  • 使 MenuItemState 状态;作为最终变量,如最终 MenuItemState 状态;将删除您的不可变警告
  • 考虑使用 GlobalKey 从另一个小部件访问状态 (stackoverflow.com/questions/46542768/…)

标签: flutter dart state


【解决方案1】:

我可以通过查看您的更多代码来更好地了解如何解决您的特定问题,但 Flutter 文档似乎会在某些方面为您提供帮助,特别是 Lifting state up 部分:

在 Flutter 中,将状态保持在使用它的小部件之上是有意义的。

为什么?在像 Flutter 这样的声明式框架中,如果你想改变 UI,你必须重新构建它。

...很难通过调用方法从外部强制更改小部件。即使你能做到这一点,你也会与框架抗争,而不是让它帮助你。

看来您正在尝试与示例中的框架作斗争,并且您担心将公共方法添加到您的 Widgets 是正确的。您需要做的是更接近文档中详细说明的内容(其中详细说明了您将在下面看到的所有新类等)。我已经基于此和使用Provider 将一个简单的示例放在一起,这使得这种状态管理方法变得容易。这是Google I/O talk from this year encouraging its use

void main() {
  runApp(
    ChangeNotifierProvider(
      builder: (context) => MenuModel(),
      child: MyApp(),
    ),
  );
}


class MyApp extends StatelessWidget {

    …

    // call this when the menu is closed
    void onMyMenuClosed(BuildContext context) {
        var menuModel = getMyMenuModel(context);
        menuModel.hideMenuItems();
    }
}



class MenuModel extends ChangeNotifier {
  
  bool _displayItems = false;
  
  void hideMenuItems() {
    _displayItems = false;
    notifyListeners();
  }
  
  void showMenuItems() {
    _displayItems = true;
    notifyListeners();
  }
}

调用hideMenuItems() 调用notifyListeners() 就可以了;通知任何侦听器的更改,这反过来会提示您重新构建 Consumer<MenuModel> 中的 Widget/s 现在,当重新构建显示菜单的 Widget 时,它只会从 @987654333 中获取适当的详细信息@class - 国家的唯一真相来源。这将您必须处理的代码路径数量减少到一个,并且在您进行进一步更改时更容易看到发生了什么。

@override
  Widget build(BuildContext context) {
    return Consumer<MenuModel>(
      builder: (context, menuModel, child) {
        return menuModel._displayItems() ? MenuItemsWidget() : Container();
      },
    );
  }

我建议你阅读entire page on state management

【讨论】:

    猜你喜欢
    • 2022-11-12
    • 2020-10-28
    • 2020-04-20
    • 1970-01-01
    • 2021-12-24
    • 2020-10-19
    • 2021-11-12
    • 2022-08-10
    • 2019-10-06
    相关资源
    最近更新 更多