如何使用 Flutter Web 处理来自提供商的全局密钥?

Posted

技术标签:

【中文标题】如何使用 Flutter Web 处理来自提供商的全局密钥?【英文标题】:How dispose Global key from provider with flutter web? 【发布时间】:2021-09-19 11:09:59 【问题描述】:

想用 Flutter web 构建抽屉。但是得到了 在小部件树中检测到重复的 GlobalKey。 实例被移动到新位置。关键是:

[LabeledGlobalKey#c9754]

GlobalKey 重设是:

MainScreen(依赖项:[MediaQuery],状态:_MainScreenState#dc897) 在小部件树中一次只能在一个小部件上指定 GlobalKey。

导入'package:flutter/material.dart';

类 MenuController 与 ChangeNotifier GlobalKey _scaffoldKey = GlobalKey();

GlobalKey<ScaffoldState> get scaffoldKey => _scaffoldKey;

void controlMenu() 
  if (!_scaffoldKey.currentState!.isDrawerOpen) 
    _scaffoldKey.currentState!.openDrawer();
  


// void disposeKey() 
//   _scaffoldKey.currentState.();
// 

类 _MainScreenState 扩展状态 @覆盖 无效初始化状态() print('init CALLED- GAME---'); super.initState();

@override
void dispose() 
  print('DISPOSE CALLED- GAME---');
  context.read<MenuController>().scaffoldKey.currentState!.dispose();
  super.dispose();


@override
Widget build(BuildContext context) 
  return Scaffold(
    key: context.read<MenuController>().scaffoldKey,
    drawer: SideMenu(),
    body: SafeArea(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // We want this side menu only for large screen
          if (Responsive.isDesktop(context))
            Expanded(
              // default flex = 1
              // and it takes 1/6 part of the screen
              child: SideMenu(),
            ),
          Expanded(
            // It takes 5/6 part of the screen
            flex: 5,
            child: DashboardScreen(),
          ),
        ],
      ),
    ),
  );

然后想重用另一个小部件的密钥

class ProductsScreen extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      key: context.read<MenuController>().scaffoldKey,
      drawer: SideMenu(),
      body: SafeArea(
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // We want this side menu only for large screen
            if (Responsive.isDesktop(context))
              Expanded(
                // default flex = 1
                // and it takes 1/6 part of the screen
                child: SideMenu(),
              ),
            Expanded(
              // It takes 5/6 part of the screen
              flex: 5,
              child: ProductsListScreen(),
            ),
          ],
        ),
      ),
    );
  

得到了错误

要在 SideMenu 小部件中导航,请使用

Navigator.pushReplacement(
                context,
                MaterialPageRoute(
                  builder: (context) => ProductsScreen(),
                ),
              );

【问题讨论】:

我记得这可以通过在每次构建时为全局键重新分配一个值来解决 谢谢,a 怎么办?在初始化时尝试了 context.read().scaffoldKey.currentState.dispose 在 dispose context.read().scaffoldKey.currentState.build(context) 但不起作用 【参考方案1】:

您无需手动处理GlobalKey。主要要求是它们不能两次插入到小部件树中。其他键不是这种情况(LocalKeys):

// this is allowed
Row(
  children: [
    SizedBox(key: Key('hello')),
    Container(key: Key('hello')),
  ],
)

// this is not
final key = GlobalKey<ScaffoldState>();
Row(
  children: [
    Scaffold(key: key),
    Scaffold(key: key),
  ],
)

违反此规定的一个常见原因是动画。在播放一个页面和另一个页面之间的动画时,两个页面都在widget树中,如果它们具有相同的GlobalKey,则会抛出错误。

调用globalKey.currentState!.dispose() 实际上会释放关联小部件的State。你不应该自己调用它。

相反,为第二个子树提供一个新的GlobalKey,或者在导航到新页面之前删除旧的。

【讨论】:

以上是关于如何使用 Flutter Web 处理来自提供商的全局密钥?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Django 为 Flutter Web 应用程序提供服务?

将提供程序包添加到 Flutter Web 项目时出错

如何在 Flutter 中使用 Provider 显示来自 ChangeNotifier 的错误

如何在 Flutter Web 中使用 Skia/CanvasKit?

Flutter Web:在 Flutter 运行时在注入的 client.js 脚本中检测到未处理的错误

如何在 Flutter Web 中扫描二维条码?