← Назад к вопросам

Как реализуешь pop-up?

1.8 Middle🔥 121 комментариев
#Flutter виджеты

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как реализуешь pop-up?

Pop-up (всплывающее окно) — один из самых часто используемых элементов UI в Flutter. Существует несколько способов его реализации в зависимости от требований и типа pop-up.

Встроенные диалоги Flutter

AlertDialog — самый простой и универсальный вариант:

showDialog(
  context: context,
  builder: (BuildContext context) {
    return AlertDialog(
      title: Text('Подтверждение\u0027),
      content: Text('Вы уверены?\u0027),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: Text('Отмена\u0027),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, true),
          child: Text('Да\u0027),
        ),
      ],
    );
  },
);

SimpleDialog для выбора

Когда нужно предоставить пользователю список выборов:

showDialog(
  context: context,
  builder: (BuildContext context) {
    return SimpleDialog(
      title: Text('Выберите опцию\u0027),
      children: [
        SimpleDialogOption(
          onPressed: () => Navigator.pop(context, 'option1\u0027),
          child: Text('Опция 1\u0027),
        ),
        SimpleDialogOption(
          onPressed: () => Navigator.pop(context, 'option2\u0027),
          child: Text('Опция 2\u0027),
        ),
      ],
    );
  },
);

Кастомный диалог

Для более сложных pop-up нужен кастомный виджет:

class CustomPopup extends StatelessWidget {
  final String title;
  final String message;
  final VoidCallback onConfirm;

  const CustomPopup({
    required this.title,
    required this.message,
    required this.onConfirm,
  });

  @override
  Widget build(BuildContext context) {
    return Dialog(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(title, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
            SizedBox(height: 16),
            Text(message),
            SizedBox(height: 24),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: () => Navigator.pop(context),
                  child: Text('Отмена\u0027),
                ),
                ElevatedButton(
                  onPressed: onConfirm,
                  child: Text('Подтвердить\u0027),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// Использование
showDialog(
  context: context,
  builder: (context) => CustomPopup(
    title: 'Заголовок\u0027,
    message: 'Сообщение\u0027,
    onConfirm: () => Navigator.pop(context),
  ),
);

BottomSheet вместо диалога

Для меню снизу используется showModalBottomSheet:

showModalBottomSheet(
  context: context,
  builder: (context) => Container(
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        ListTile(
          title: Text('Опция 1\u0027),
          onTap: () => Navigator.pop(context),
        ),
        ListTile(
          title: Text('Опция 2\u0027),
          onTap: () => Navigator.pop(context),
        ),
      ],
    ),
  ),
);

Анимированный pop-up

Для красивой анимации используется PopScope и AnimatedBuilder:

class AnimatedPopup extends StatefulWidget {
  @override
  State<AnimatedPopup> createState() => _AnimatedPopupState();
}

class _AnimatedPopupState extends State<AnimatedPopup> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(duration: Duration(milliseconds: 300), vsync: this);
    _animation = Tween<double>(begin: 0, end: 1).animate(_controller);
    _controller.forward();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ScaleTransition(
      scale: _animation,
      child: AlertDialog(
        title: Text('Анимированный диалог\u0027),
        content: Text('С красивой анимацией\u0027),
      ),
    );
  }
}

Рекомендации

  • AlertDialog — для простых подтверждений
  • SimpleDialog — для выбора из списка
  • BottomSheet — для меню снизу экрана
  • Кастомный Dialog — для сложного UI
  • GetX или Provider — для управления состоянием pop-up

Лучшая практика — создать переиспользуемый utility класс для всех диалогов в приложении, чтобы обеспечить консистентность UI и легко менять стиль глобально.