[flutter]在小部件上显示对话框

时间:2018-08-28 13:23:20

标签: dart flutter

在扑朔迷离中,我们想在小部件上方覆盖一个对话框。

按下按钮后,我们就可以显示对话框。

但是,我们希望在显示喜欢加载对话框的小部件时显示该对话框。

我们实现了如下。

import 'package:flutter/material.dart';

class XxxxxWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // [NG]We want to show dialog on Container widget.
    // showMyDialog(context);
    return Container(
      child: FlatButton(
        child: Text('Show'),
        onPressed: () {
          // [OK]We can show dialog.
          showMyDialog(context);
        },
      ),
    );
  }

  void showMyDialog(BuildContext context) {
    showDialog<bool>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          content: const Text(
            'Message',
          ),
          actions: <Widget>[
            FlatButton(
              child: const Text('OK'),
              onPressed: () {
                Navigator.of(context).pop(true);
              },
            ),
          ],
        );
      },
    );
  }
}

当我们使用[NG]代码时,会发生以下错误。

I/flutter (28618): When the exception was thrown, this was the stack:
I/flutter (28618): #0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3436:11)
I/flutter (28618): #1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3462:6)
I/flutter (28618): #2      State.setState (package:flutter/src/widgets/framework.dart:1141:14)
I/flutter (28618): #3      OverlayState.insertAll (package:flutter/src/widgets/overlay.dart:301:5)
I/flutter (28618): #4      OverlayRoute.install (package:flutter/src/widgets/routes.dart:40:24)
I/flutter (28618): #5      TransitionRoute.install (package:flutter/src/widgets/routes.dart:182:11)
I/flutter (28618): #6      ModalRoute.install (package:flutter/src/widgets/routes.dart:740:11)
I/flutter (28618): #7      NavigatorState.push (package:flutter/src/widgets/navigator.dart:1443:11)
I/flutter (28618): #8      showDialog (package:flutter/src/material/dialog.dart:642:53)
I/flutter (28618): #9      XxxxxWidget.showMyDialog (package:xxxxx/Widgets/xxxxx_widget.dart:20:5)
I/flutter (28618): #10     XxxxxWidget.build (package:xxxxx/Widgets/xxxxx_widget.dart:7:5)
[abridgement]

我们也尝试过FutureBuilder,但无法解决此问题。

我们应该如何解决这个问题?

$ flutter doctor -v
[✓] Flutter (Channel beta, v0.5.1, on Mac OS X 10.13.6 17G65, locale ja)
    • Flutter version 0.5.1 at /Applications/flutter
    • Framework revision c7ea3ca377 (3 months ago), 2018-05-29 21:07:33 +0200
    • Engine revision 1ed25ca7b7
    • Dart version 2.0.0-dev.58.0.flutter-f981f09760

[✓] Android toolchain - develop for Android devices (Android SDK 27.0.3)
    • Android SDK at /Users/xxxxx/src/android-sdks
    • Android NDK at /Users/xxxxx/src/android-sdks/ndk-bundle
    • Platform android-27, build-tools 27.0.3
    • ANDROID_HOME = /Users/xxxxx/src/android-sdks
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)
    • All Android licenses accepted.

[✓] iOS toolchain - develop for iOS devices (Xcode 9.4.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 9.4.1, Build version 9F2000
    • ios-deploy 1.9.2
    • CocoaPods version 1.5.3

[✓] Android Studio (version 3.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 27.1.1
    • Dart plugin version 173.4700
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)

[!] VS Code (version 1.25.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension not installed; install from
      https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected devices (1 available)
    • ASUS Z017DA • XXXXXXXXXXXXXXX • android-arm64 • Android 8.0.0 (API 26)

! Doctor found issues in 1 category.

我们已经安装了Flutter扩展程序。 但是扑扑医生说没装好。 这对于这个问题并不重要。

4 个答案:

答案 0 :(得分:7)

我们必须完成,并在构建窗口小部件后显示该对话框。 您可以使用如下所示的 Future.delayed 功能(我已进行了测试,它正在工作)。

class XxxxxWidget extends StatelessWidget {

@override
Widget build(BuildContext context) {
// [NG]We want to show dialog on Container widget.

 Future.delayed(Duration.zero, () => showMyDialog(context)); // import 'dart:async';
 return Container(
  child: FlatButton(.... //same as question

说明:

由于Dart基于单线程事件循环,因此当我们创建异步任务时,它将把这些事件放在事件队列的末尾并继续其当前执行。请参考下面的示例以获取更多详细信息,

void main() {
  print("first");
  Future(() => print("second"));
  print("third");
  Future(() => print("forth"));

}

输出将为

first
third
second
forth

它与

非常相似
DispatchQueue.main.async {
 print("Async1") //printJob
}

完成building the widget后,将显示dialog。看看我的answer有没有类似的问题。

答案 1 :(得分:1)

其中有些模棱两可,但是您可以在这样的小部件初始化方法中显示警报对话框

Future showDialog() async {

 WidgetsBinding.instance.addPostFrameCallback((_) async {
  await showDialog<String>(
    context: context,
    builder: (BuildContext context) => AlertDialog(
          title: const Text('Title'),
          content: const Text('Content')
          actions: <Widget>[
            FlatButton(
              child: const Text('OK'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        ),
  );
});
}

这将等待绘制第一帧,然后显示对话框,以便您可以从init调用它

@override
  void initState() {
   super.initState();

   showDialog();
}

答案 2 :(得分:0)

您在Flutter上遇到的问题很正常,因此让我们看一下代码。

我猜问题出在Widget的构造函数中,需要像这样:

showMyDialog(BuildContext context) {
 showDialog(
  context: context,
  builder: (BuildContext context){
  return new AlertDialog(
    content: Text(
        'Message Here',
      ),
      actions: <Widget>[
        FlatButton(
          child: const Text('OK'),
          onPressed: () {
            Navigator.of(context).pop(true);
          },
        ),
      ],
   );
  }
 );
}

尝试

答案 3 :(得分:0)

执行此操作的“颤振方式”如下所示(假定在渲染主屏幕时需要执行此操作):

class MyWidgetWithDialogOnStartup extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: FutureBuilder(
        future: Future.delayed(Duration.zero, () => showMyDialog(context)),
        builder: (context, snapshot) {
          return WhateverMyWidgetReallyIs();
        },
      )
    );
  }
}

showMyDialog(context)包装了本地showDialog调用。