Kodokon kodokon.com

Navegar entre pantallas con Navigator

Apila y desapila pantallas con Navigator.push y pop, pasa datos a través de los constructores y recupera un resultado cuando la pantalla se cierra.

8 min · 3 preguntas

Abrir esta lección en Kodokon

Flutter gestiona tus pantallas como una pila: Navigator.push coloca una nueva pantalla encima, Navigator.pop retira la de arriba y revela la anterior. Cada pantalla es una ruta, y MaterialPageRoute proporciona la transición nativa de la plataforma. El botón de retroceso de Android invoca pop por ti, sin una sola línea de código.

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 apila DetailScreen (definido más abajo) encima de la pantalla actual.

Para pasar datos a la siguiente pantalla, no hay ningún mecanismo mágico: la pantalla de destino es un widget como cualquier otro, y recibe sus datos a través de su constructor. Es tipado, explícito, y el compilador te avisa si falta un campo. Ten en cuenta que la AppBar de la pantalla apilada muestra el botón de retroceso sin que escribas nada.

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 cierra la pantalla y devuelve un valor a quien la llamó.

Navigator.push devuelve un Future que se completa cuando la pantalla se cierra, con el valor pasado a pop. Por lo tanto, puedes esperar el resultado de una pantalla: una confirmación, un elemento elegido de una lista, un formulario rellenado. El tipo genérico push<bool> documenta lo que esperas recibir de vuelta.

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)),
  );
}
El Future de push se completa cuando la pantalla se cierra.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. ¿Cómo organiza Navigator las pantallas?
    • Como una cola: el primero en entrar, el primero en mostrarse
    • Como una pila: la última pantalla apilada se muestra encima
    • Como un árbol de widgets paralelo
    • Como una cuadrícula de pantallas
  2. ¿Cuál es la forma idiomática de pasar datos a la siguiente pantalla?
    • A través de una variable global
    • Mediante el constructor del widget de destino
    • Escribiéndolos en el disco
    • Navigator no permite pasar datos
  3. ¿Qué hace Navigator.pop(context, true)?
    • Abre una nueva pantalla llamada "true"
    • Cierra todas las pantallas de la pila
    • Cierra la pantalla actual y devuelve true al push que está esperando