Flutter:showGeneralDialog与原始调用showGeneralDialog的位置不共享上下文

3

问题:

我的showGeneralDialog创建方法如下: (我在动画显示对话框的onShow和onPop上, 所以我使用了TransitionBuilder而不是PageBuilder)

  void _showSignOutAlert(BuildContext context) {
    showGeneralDialog(
      barrierColor: Colors.black.withOpacity(0.5),
      transitionBuilder: (context, a1, a2, widget) {
        return Transform.scale(
          scale: a1.value,
          child: Opacity(
            opacity: a1.value,
            child: CustomWidget(),
          ),
        );
      },
      transitionDuration: Duration(milliseconds: 250),
      barrierDismissible: true,
      context: context,
      pageBuilder: (context, animation1, animation2) {
        return null;
      },
    );
  }

我正在从一个StatelessWidget中调用_showSignOutAlert(),并在参数中传递StatelessWidget-context。

我正在使用Provider-package,并在StatelessWidget上方定义了ChangeNotifierProvider-builder,该builder调用了_showSignOutAlert()

当尝试从showGeneralDialog()创建的CustomWidget中访问Provider时,它会提示找不到Provider。

来自于flutter关于showGeneralDialog()的说明文档:

此函数采用pageBuilder,用于构建路线的主要内容(通常是对话框小部件)。 对话框下方的内容会被[ModalBarrier]阻隔。 pageBuilder返回的小部件与最初从showGeneralDialog调用的位置不共享上下文。 如果对话框需要动态更新,请使用[StatefulBuilder]或自定义[StatefulWidget]。 pageBuilder参数不能为空。

问题:

我不知道如何继续操作以能够从CustomWidget访问Provider?


1
你可以通过这个 Provider.of<>(context) 获取到 provider,就像你已经提到的那样。那么你有什么问题吗? - Vrushi Patel
@Vrushi Patel 的确,现在它可以工作了,尽管也许还有另一种方法来获取 CustomWidget 中调用 showGeneralDialog() 的小部件的上下文,而不是将其作为参数传递给 CustomWidget。可能没有其他的方法,我的更新是唯一正确的答案。 - SimonartM
@Vrushi Patel,我删除了更新并将其作为可能的答案。 - SimonartM
3个回答

2

正确的方式:

void _showSignOutAlert(BuildContext context) {
  final CapturedThemes themes = InheritedTheme.capture(
    from: context,
    to: Navigator.of(
        context,
        rootNavigator: true,
    ).context,
  );

  showGeneralDialog(
    barrierColor: Colors.black.withOpacity(0.5),
    transitionBuilder: (context, a1, a2, widget) {
      return Transform.scale(
        scale: a1.value,
        child: Opacity(
          opacity: a1.value,
          child: widget,
        ),
      );
    },
    transitionDuration: Duration(milliseconds: 250),
    barrierDismissible: true,
    context: context,
    pageBuilder: (context, animation1, animation2) {
      return themes.wrap(Builder(
        builder: (context) => CustomWidget(),
      ));
    },
  );
}

注意: CapturedThemesthemes.wrap

谢谢!那绝对是正确的方式! - Yannick Mauray

1

将 useRootNavigator 设置为 false

https://api.flutter.dev/flutter/widgets/showGeneralDialog.html

useRootNavigator参数用于确定将对话框推送到距离给定上下文最远的导航器或最近的导航器。默认情况下,useRootNavigator为true,由此方法创建的对话框路由将被推送到根导航器。

哦,我的天啊,你真是救了我一命。我花了好几个小时才弄明白为什么对话框没有关闭,而是弹出了我的页面。我不知道为什么上下文不同。 - Arie Agung

1
我成功地传达了上下文,通过以下方法:

  void _showSignOutAlert(BuildContext superContext) {
    showGeneralDialog(
      barrierColor: Colors.black.withOpacity(0.5),
      transitionBuilder: (context, a1, a2, widget) {
        return Transform.scale(
          scale: a1.value,
          child: Opacity(
            opacity: a1.value,
            child: CustomWidget(superContext: superContext),
          ),
        );
      },
      transitionDuration: Duration(milliseconds: 250),
      barrierDismissible: true,
      context: superContext,
      pageBuilder: (context, animation1, animation2) {
        return null;
      },
    );
  }

然后在CustomWidget中使用superContext调用Provider.of<State>(superContext)

但如果有其他解决方案,我很乐意听取建议。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接