在扑朔迷离中,我们想在小部件上方覆盖一个对话框。
按下按钮后,我们就可以显示对话框。
但是,我们希望在显示喜欢加载对话框的小部件时显示该对话框。
我们实现了如下。
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扩展程序。 但是扑扑医生说没装好。 这对于这个问题并不重要。
答案 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
调用。