Отображение AlertDialog без Context в Flutter

Отображение AlertDialog без Context в Flutter

FlutterPulse

Эта статья переведена специально для канала FlutterPulse. В этом канале вы найдёте много интересных вещей, связанных с Flutter. Не забывайте подписываться! 🚀

Проблема: Отображение AlertDialog без контекста

Проблема: Отображение AlertDialog без контекста

В Flutter функция showDialog требует параметра BuildContext. Однако, если мы хотим показать AlertDialog из асинхронной функции (например, при ошибке HTTP-запроса внутри getNews()), у нас может не быть прямого доступа к context.

Распространённая ошибка: Попытка показать диалог без контекста

Распространённая ошибка среди новичков — попытка показать диалог непосредственно внутри асинхронной функции без передачи корректного context. Например:

void getNews() async {
try {
throw Exception("Failed to load news");
} catch (e) {
print("Error: \$e");
showDialog(
context: context, // ❌ Ошибка: контекст недоступен здесь
builder: (context) => AlertDialog(
title: Text("Error"),
content: Text("Something went wrong!"),
),
);
}
}

Этот код не будет работать, потому что context недоступен в независимой функции.

Решение: Использование GlobalKey<NavigatorState>

Чтобы решить эту проблему, можно использовать глобальный navigatorKey. Это позволяет получить доступ к BuildContext глобально и показать диалог из любой части приложения, даже внутри асинхронной функции.

Пошаговое руководство

Шаг 1: Определение глобального ключа навигатора

Глобальный ключ навигатора позволяет управлять навигацией без необходимости в context. Объявите его в самом верху файла main.dart, вне любых классов:

import 'package:flutter/material.dart';

// ✅ Правильно: Объявите глобальный ключ навигатора вверху
final navigatorKey = GlobalKey<NavigatorState>();

Шаг 2: Назначение MaterialApp

При инициализации MaterialApp назначьте navigatorKey ему:

void main() => runApp(
MaterialApp(
home: HomePage(),
navigatorKey: navigatorKey, // ✅ Назначьте глобальный ключ навигатора
),
);

Шаг 3: Создание функции для показа AlertDialog

Теперь создайте функцию, которую можно вызывать из любой части приложения для отображения AlertDialog:

void showMyDialog() {
showDialog(
context: navigatorKey.currentContext!, // ✅ Использование глобального контекста
builder: (context) => AlertDialog(
title: Text("Error"),
content: Text("Something went wrong!"),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text("OK"),
),
],
),
);
}

Шаг 4: Триггер диалога при ошибке HTTP

В вашей асинхронной функции вызовите showMyDialog() при возникновении ошибки:

Future<void> getNews() async {
try {
// Имитация HTTP-запроса
throw Exception("Failed to load news");
} catch (e) {
print("Error: \$e"); // ✅ Запись ошибки
showMyDialog(); // ✅ Показать AlertDialog
}
}

Шаг 5: Полный рабочий пример кода

Вот полный пример, чтобы новички могли увидеть, как всё собирается вместе:

import 'package:flutter/material.dart';

final navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(MaterialApp(
home: HomePage(),
navigatorKey: navigatorKey,
));
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Home")),
body: Center(
child: ElevatedButton(
onPressed: getNews,
child: Text("Fetch News"),
),
),
);
}
}
void showMyDialog() {
showDialog(
context: navigatorKey.currentContext!,
builder: (context) => AlertDialog(
title: Text("Error"),
content: Text("Something went wrong!"),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text("OK"),
),
],
),
);
}
Future<void> getNews() async {
try {
throw Exception("Failed to load news");
} catch (e) {
print("Error: \$e");
showMyDialog();
}
}

Почему это работает

  • Неправильный подход: Использование context внутри асинхронной функции.
  • Правильный подход: Использование navigatorKey для получения глобального context.
  • Функция showMyDialog() может быть вызвана из любого места, включая асинхронные функции.
  • Этот подход помогает избежать необходимости явного передачи context, делая код чище.

Report Page