Saltar al contenido principal

Enviar datos a una nueva pantalla

Cómo pasar datos a una nueva ruta.

A menudo, no solo quieres navegar a una nueva pantalla, sino también pasar datos a dicha pantalla. Por ejemplo, es posible que quieras pasar información sobre el elemento que se ha tocado.

Recuerda: las pantallas son simplemente Widgets. En este ejemplo, crea una lista de todos. Cuando se toque un todo, navega a una nueva pantalla (Widget) que muestre información sobre ese todo. Esta receta utiliza los siguientes pasos:

  1. Definir una clase todo.
  2. Mostrar una lista de todos.
  3. Crear una pantalla de detalles que pueda mostrar información sobre un todo.
  4. Navegar y pasar datos a la pantalla de detalles.

1. Definir una clase todo

#

Primero, necesitas una forma sencilla de representar los todos. Para este ejemplo, crea una clase que contenga dos fragmentos de datos: el título y la descripción.

dart
class Todo {
  final String title;
  final String description;

  const Todo(this.title, this.description);
}

2. Crear una lista de todos

#

Segundo, muestra una lista de todos. En este ejemplo, genera 20 todos y muéstralos usando un ListView. Para obtener más información sobre cómo trabajar con listas, consulta la receta Usar listas.

Generar la lista de todos

#
dart
final todos = List.generate(
  20,
  (i) => Todo(
    'Todo $i',
    'A description of what needs to be done for Todo $i',
  ),
);

Mostrar la lista de todos usando un ListView

#
dart
ListView.builder(
  itemCount: todos.length,
  itemBuilder: (context, index) {
    return ListTile(title: Text(todos[index].title));
  },
)

Hasta aquí todo bien. Esto genera 20 todos y los muestra en un ListView.

3. Crear una pantalla de Todo para mostrar la lista

#

Para esto, creamos un StatelessWidget. Lo llamamos TodosScreen. Dado que el contenido de esta página no cambiará durante el tiempo de ejecución, tendremos que requerir la lista de todos dentro del alcance de este Widget.

Pasamos nuestro ListView.builder como body del Widget que estamos devolviendo en build(). ¡Esto renderizará la lista en la pantalla para que puedas comenzar!

dart
class TodosScreen extends StatelessWidget {
  // Requiring the list of todos.
  const TodosScreen({super.key, required this.todos});

  final List<Todo> todos;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Todos')),
      //passing in the ListView.builder
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return ListTile(title: Text(todos[index].title));
        },
      ),
    );
  }
}

Con el estilo predeterminado de Flutter, ¡estás listo para comenzar sin preocuparte por las cosas que te gustaría hacer más adelante!

4. Crear una pantalla de detalles para mostrar información sobre un todo

#

Now, create the second screen. The title of the screen contains the title of the todo, and the body of the screen shows the description.

Dado que la pantalla de detalles es un StatelessWidget normal, requiere que el usuario introduzca un Todo en la UI. Luego, construye la UI utilizando el todo dado.

dart
class DetailScreen extends StatelessWidget {
  // In the constructor, require a Todo.
  const DetailScreen({super.key, required this.todo});

  // Declare a field that holds the Todo.
  final Todo todo;

  @override
  Widget build(BuildContext context) {
    // Use the Todo to create the UI.
    return Scaffold(
      appBar: AppBar(title: Text(todo.title)),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Text(todo.description),
      ),
    );
  }
}

5. Navegar y pasar datos a la pantalla de detalles

#

Con la pantalla DetailScreen en su lugar, estás listo para realizar la navegación. En este ejemplo, navega a la pantalla DetailScreen cuando el usuario toque un todo en la lista. Pasa el todo a la pantalla DetailScreen.

Para capturar el toque del usuario en la pantalla TodosScreen, escribe una función callback onTap() para el Widget ListTile. Dentro del callback onTap(), utiliza el método Navigator.push().

dart
body: ListView.builder(
  itemCount: todos.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(todos[index].title),
      // When a user taps the ListTile, navigate to the DetailScreen.
      // Notice that you're not only creating a DetailScreen, you're
      // also passing the current todo through to it.
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute<void>(
            builder: (context) => DetailScreen(todo: todos[index]),
          ),
        );
      },
    );
  },
),

Ejemplo interactivo

#

Alternativamente, pasar los argumentos usando RouteSettings

#

Repetir los dos primeros pasos.

Crear una pantalla de detalles para extraer los argumentos

#

A continuación, crea una pantalla de detalles que extraiga y muestre el título y la descripción del Todo. Para acceder al Todo, utiliza el método ModalRoute.of(). Este método devuelve la ruta actual con los argumentos.

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

  @override
  Widget build(BuildContext context) {
    final todo = ModalRoute.of(context)!.settings.arguments as Todo;

    // Use the Todo to create the UI.
    return Scaffold(
      appBar: AppBar(title: Text(todo.title)),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Text(todo.description),
      ),
    );
  }
}
#

Finalmente, navega a la pantalla DetailScreen cuando un usuario toque un Widget ListTile usando Navigator.push(). Pasa los argumentos como parte de los RouteSettings. La pantalla DetailScreen extraerá estos argumentos.

dart
ListView.builder(
  itemCount: todos.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(todos[index].title),
      // When a user taps the ListTile, navigate to the DetailScreen.
      // Notice that you're not only creating a DetailScreen, you're
      // also passing the current todo through to it.
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute<void>(
            builder: (context) => const DetailScreen(),
            // Pass the arguments as part of the RouteSettings. The
            // DetailScreen reads the arguments from these settings.
            settings: RouteSettings(arguments: todos[index]),
          ),
        );
      },
    );
  },
)

Ejemplo completo

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

class Todo {
  final String title;
  final String description;

  const Todo(this.title, this.description);
}

void main() {
  runApp(
    MaterialApp(
      title: 'Passing Data',
      home: TodosScreen(
        todos: List.generate(
          20,
          (i) => Todo(
            'Todo $i',
            'A description of what needs to be done for Todo $i',
          ),
        ),
      ),
    ),
  );
}

class TodosScreen extends StatelessWidget {
  const TodosScreen({super.key, required this.todos});

  final List<Todo> todos;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Todos')),
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(todos[index].title),
            // When a user taps the ListTile, navigate to the DetailScreen.
            // Notice that you're not only creating a DetailScreen, you're
            // also passing the current todo through to it.
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute<void>(
                  builder: (context) => const DetailScreen(),
                  // Pass the arguments as part of the RouteSettings. The
                  // DetailScreen reads the arguments from these settings.
                  settings: RouteSettings(arguments: todos[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final todo = ModalRoute.of(context)!.settings.arguments as Todo;

    // Use the Todo to create the UI.
    return Scaffold(
      appBar: AppBar(title: Text(todo.title)),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Text(todo.description),
      ),
    );
  }
}