Как реализовать pop-up в Flutter?

«Как реализовать pop-up в Flutter?» — вопрос из категории UI и вёрстка, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Flutter есть несколько встроенных виджетов для реализации всплывающих окон (pop-up), выбор зависит от типа взаимодействия:

1. AlertDialog — для стандартных диалогов с подтверждением или выбором:

await showDialog(
  context: context,
  builder: (context) => AlertDialog(
    title: Text('Подтверждение'),
    content: Text('Вы уверены, что хотите удалить элемент?'),
    actions: [
      TextButton(
        onPressed: () => Navigator.pop(context, false),
        child: Text('Отмена'),
      ),
      TextButton(
        onPressed: () => Navigator.pop(context, true),
        child: Text('Удалить'),
      ),
    ],
  ),
);

2. SnackBar — для кратковременных уведомлений без блокировки интерфейса:

ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: Text('Элемент удалён'),
    duration: Duration(seconds: 2),
    action: SnackBarAction(
      label: 'Отменить',
      onPressed: () => undoDelete(),
    ),
  ),
);

3. ModalBottomSheet — для выбора из нескольких опций или отображения дополнительного контента:

await showModalBottomSheet(
  context: context,
  builder: (context) => Container(
    padding: EdgeInsets.all(16),
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        ListTile(
          leading: Icon(Icons.share),
          title: Text('Поделиться'),
          onTap: () {
            Navigator.pop(context);
            shareContent();
          },
        ),
        ListTile(
          leading: Icon(Icons.copy),
          title: Text('Копировать'),
          onTap: () {
            Navigator.pop(context);
            copyToClipboard();
          },
        ),
      ],
    ),
  ),
);

4. Custom Dialog — для сложных кастомных попапов:

await showDialog(
  context: context,
  barrierDismissible: false, // Запрет закрытия по клику вне диалога
  builder: (context) => Dialog(
    child: Container(
      padding: EdgeInsets.all(20),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('Кастомный диалог', style: TextStyle(fontSize: 18)),
          SizedBox(height: 20),
          TextField(decoration: InputDecoration(hintText: 'Введите текст')),
          SizedBox(height: 20),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: Text('Закрыть'),
              ),
            ],
          ),
        ],
      ),
    ),
  ),
);

Ключевые моменты:

  • Все диалоги требуют BuildContext для навигации
  • showDialog возвращает Future<T>, что позволяет получать результат выбора пользователя
  • Для SnackBar в MaterialApp 3.x используйте ScaffoldMessenger вместо прямого доступа к Scaffold
  • Для сложных анимаций можно использовать Overlay напрямую или пакеты вроде fluttertoast для тостов