AlertDialog без контекста во флаттере
Я хочу показать AlertDialog, когда не удается получить http. Функция showDialog ( https://api.flutter.dev/flutter/material/showDialog.html) имеет параметр "@required BuildContext context", но я хочу вызвать AlertDialog из моей асинхронной функции getNews(), которая не имеет значение контекста.
По аналогии с Java, где я использую null для диалога без владельца, я пытался установить значение контекста в null, но это не принято.
Это мой код:
Future<dynamic> getNews() async {
dynamic retVal;
try {
var response = await http.get(url));
if (response.statusCode == HttpStatus.ok) {
retVal = jsonDecode(response.body);
}
} catch (e) {
alertDlg(?????????, 'Error', e.toString());
}
return
retVal;
}
static Future<void> alertDlg(context, String titolo, String messaggio) async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text(titolo),
...
);
}
6 ответов
Решение без сторонних библиотек и хранения BuildContext
:
final navigatorKey = GlobalKey<NavigatorState>();
void main() => runApp(
MaterialApp(
home: HomePage(),
navigatorKey: navigatorKey, // Setting a global key for navigator
),
);
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: Center(
child: Text('test')
)
),
floatingActionButton: FloatingActionButton(
onPressed: showMyDialog, // Calling the function without providing it BuildContext
),
);
}
}
void showMyDialog() {
showDialog(
context: navigatorKey.currentState.overlay.context, // Using overlay's context
builder: (context) => Center(
child: Material(
color: Colors.transparent,
child: Text('Hello'),
),
)
);
}
После установки глобального ключа навигатора (navigatorKey
параметр MaterialApp
class), его текущее состояние становится доступным из любой части кода. Мы можем использовать ребенкаOverlayState
контекст из текущего NavigatorState
пример. Это немного взломано, но, на мой взгляд, неплохо. Убедитесь, что вы не используете его до построения первого кадра, иначе состояние будет нулевым.
По сути, диалоги - это просто еще один тип маршрута, например MaterialPageRoute
или CupertinoPageRoute
- все они получены из ModalRoute
class и их экземпляры помещаются в NavigatorState
. Контекст нужен только для получения текущего состояния навигатора. Новый маршрут можно отправить без контекста, если у нас есть глобальная клавиша навигатора:
navigatorKey.currentState.push(route)
К сожалению, _DialogRoute
класс (...\flutter\lib\src\widgets\routes.dart), используемый в showDialog
Функция закрыта и недоступна, но вы создаете свой собственный класс маршрута диалога и помещаете его в стек навигатора.
Принятый ответ неверен.
Диалогу нужен контекст только для доступа к нему через унаследованный navigateState. Вы можете создать свой собственный измененный диалог или использовать для этого эту библиотеку.
С его помощью вы можете открыть диалог из любого места вашего кода без контекста, выполнив следующие действия:
Get.dialog(SimpleDialog());
Поймайте исключение, когда вы делаете вызов getNews, если используете await, иначе используйте свойство catchError объекта Future.
Итак, вам нужен BuildContext
для создания диалога, но у вас нет к нему доступа. Это распространенная проблема, вы можете обратиться к этому вопросу Stackru, чтобы узнать об одном из подходов к ее решению (создать статический диалог и показать его из любого места).
Другой подход, который вы можете рассмотреть, - передать контекст при создании асинхронного метода или объекта в качестве аргумента. Убедитесь, что вы обнулили его, когда закончите.
Или вы можете сделать флаг (логический), который становится "истинным" при определенных условиях, и в одном из build()
методы, вы всегда проверяете этот флаг, и если он "истина" - делайте свое дело (например, покажите диалог).
Самый простой способ показать предупреждение в любом месте: используйте эту ссылку на пакет и введите эти строки везде, где вы хотите показать предупреждение:
QuickAlert.show( context: context, type: QuickAlertType.error, text: 'Error Message');
- Установите GetX с помощью: flutter pub add get
- создать диалог с помощью Get.dialog
- добавьте эту строку
Get.dialog(
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 40),
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Material(
child: Column(
children: [
const Text("Dialog with GetX without context")
Row(
children: [
const SizedBox(width: 10),
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size(0, 45),
primary: Colors.green,
onPrimary: const Color(0xFFFFFFFF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
onPressed: () {
Navigator.pop(Get.overlayContext!, true);
},
child: const Text(
'Cerrar',
),
),
),
],
),
],
),
),
),
),
),
],
),
);
сделанный!