Kodokon kodokon.com

Навигация между экранами с Navigator

Открывай и закрывай экраны через Navigator.push и pop, передавай данные через конструкторы и получай результат, когда экран закрывается.

8 мин · 3 вопросов

Открыть этот урок в Kodokon

Flutter управляет твоими экранами как стеком: Navigator.push кладёт новый экран сверху, Navigator.pop убирает верхний и показывает предыдущий. Каждый экран - это маршрут (route), а MaterialPageRoute даёт нативный переход платформы. Кнопка «Назад» на Android вызывает pop за тебя, без единой строчки кода.

DART
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Center(
        child: FilledButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) {
                  return const DetailScreen(
                    productName: 'Headphones',
                  );
                },
              ),
            );
          },
          child: const Text('View product'),
        ),
      ),
    );
  }
}
push кладёт DetailScreen (описан ниже) поверх текущего экрана.

Чтобы передать данные на следующий экран, никакого волшебного механизма нет: экран назначения - это такой же виджет, как любой другой, и он получает свои данные через конструктор. Это типизировано, явно, и компилятор поймает тебя, если поля не хватает. Заметь, что AppBar открытого экрана показывает кнопку «Назад» без единой написанной тобой строчки.

DART
import 'package:flutter/material.dart';

class DetailScreen extends StatelessWidget {
  const DetailScreen({
    super.key,
    required this.productName,
  });

  final String productName;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(productName)),
      body: Center(
        child: FilledButton(
          onPressed: () {
            Navigator.pop(context, true);
          },
          child: const Text('Add to cart'),
        ),
      ),
    );
  }
}
pop закрывает экран и возвращает значение вызывающей стороне.

Navigator.push возвращает Future, который завершается при закрытии экрана значением, переданным в pop. Значит, ты можешь дождаться результата экрана: подтверждения, выбранного из списка элемента, заполненной формы. Обобщённый тип push<bool> документирует, что именно ты ожидаешь получить назад.

DART
import 'package:flutter/material.dart';

Future<void> openDetail(BuildContext context) async {
  final added = await Navigator.push<bool>(
    context,
    MaterialPageRoute<bool>(
      builder: (context) {
        return const DetailScreen(
          productName: 'Headphones',
        );
      },
    ),
  );
  if (!context.mounted) return;
  final message = (added ?? false)
      ? 'Product added to cart'
      : 'No product added';
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text(message)),
  );
}
Future от push завершается, когда экран закрывается.

Проверка знаний

Убедись, что запомнил ключевые моменты этого урока.

  1. Как Navigator организует экраны?
    • Как очередь: кто первым вошёл, тот первым и показан
    • Как стек: последний добавленный экран показан сверху
    • Как параллельное дерево виджетов
    • Как сетку экранов
  2. Как идиоматично передать данные на следующий экран?
    • Через глобальную переменную
    • Через конструктор виджета назначения
    • Записав их на диск
    • Navigator не позволяет передавать данные
  3. Что делает Navigator.pop(context, true)?
    • Открывает новый экран с именем «true»
    • Закрывает все экраны в стеке
    • Закрывает текущий экран и возвращает true ожидающему push