[флаттер] Показать диалог на виджете
Во флаттере мы хотим наложить диалоговое окно над виджетом.
Мы смогли отобразить диалог после нажатия кнопки.
Однако мы хотим отобразить это диалоговое окно во время отображения виджета, который любит диалог загрузки.
Мы реализовали следующим образом.
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. Но трепетать доктор сказал не установлено. Это не важно для этого вопроса.
2 ответа
Мы должны отобразить диалоговое окно, когда закончится построение виджета. Вы можете использовать функцию 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
Explaination:
Поскольку 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
, Проверьте мой ответ для аналогичной проблемы.
Некоторые из них неоднозначны, но вы можете показать диалоговое окно с предупреждением в методе инициализации виджетов, подобном этому
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();
}
Проблема у вас нормальная на Флаттере, так что давайте посмотрим код.
Я предполагаю, что проблема в конструкторе для виджета, должно быть так:
showMyDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuilderContext context){
return new AlertDialog(
content: Text(
'Message',
),
actions: <Widget>[
FlatButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop(true);
},
),
],
);
}
);
}
Попробуй это
"Путь Flutter" для этого будет выглядеть так (предположим, вам нужно сделать это при рендеринге главного экрана):
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
вызов.