새로운 화면으로 데이터 보내기

종종 새로운 화면으로 단순히 이동하는 것 뿐만 아니라 데이터를 넘겨주어야 할 때도 있습니다. 예를 들어, 사용자가 선택한 아이템에 대한 정보를 같이 넘겨주고 싶은 경우가 있습니다.

기억하세요: 화면은 단지 위젯입니다. 이 예제에서 Todo 리스트를 만들 것입니다. Todo를 선택하면 새로운 화면(위젯)으로 이동하면서 선택한 todo에 대한 정보를 보여줄 것입니다. 여기서는 아래와 같은 단계로 진행합니다:

  1. Todo 클래스를 정의합니다.
  2. Todo 리스트를 보여줍니다.
  3. Todo에 대한 상세 정보를 보여줄 수 있는 화면을 생성합니다.
  4. 상세 화면으로 이동하면서 데이터를 전달합니다.

1. Todo 클래스를 정의합니다.

우선 Todo를 표현하기 위한 간단한 정보가 필요합니다. 이 예제에서는 두 가지의 데이터를 갖고 있는 클래스를 정의할 것입니다: 제목과 상세 설명

class Todo {
  final String title;
  final String description;

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

2. Todo 리스트를 보여줍니다.

두 번째로, Todo 리스트를 보여줄 것입니다. 이 예제에서는 20개의 todo를 생성하고 ListView를 사용하여 보여줄 것입니다. List에 대한 더 자세한 정보는 Use lists에서 확인할 수 있습니다.

Todo 리스트 생성하기

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

ListView를 사용하여 Todo 리스트 보여주기

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

여기까지 그런대로 잘 되었습니다. 이제 20개의 Todo를 생성하여 ListView에 보여줄 것입니다!

3. Todo에 대한 상세 정보를 보여줄 수 있는 화면을 생성합니다.

이제 두 번째 화면을 만들겠습니다. 화면의 제목은 Todo의 제목을 포함하며 본문에는 상세 설명을 보여줄 것입니다.

두 번째 화면은 일반적인 StatelssWidget이므로, 생성자 매개변수로 Todo를 받을 수 있게 간단한 방법으로 강제하겠습니다. 그러면 주어진 Todo를 활용하여 UI를 그릴 수 있습니다.

class DetailScreen extends StatelessWidget {
  // Todo를 들고 있을 필드를 선언합니다.
  final Todo todo;

  // 생성자 매개변수로 Todo를 받도록 강제합니다.
  DetailScreen({Key key, @required this.todo}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // UI를 그리기 위해 Todo를 사용합니다.
    return Scaffold(
      appBar: AppBar(
        title: Text(todo.title),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Text(todo.description),
      ),
    );
  }
}

4. 상세 화면으로 이동하면서 데이터를 전달합니다.

앞서 작성한 DetailsScreen으로 화면 전환할 준비가 되었습니다. 본 예제에서는 사용자가 Todo 리스트 중 하나를 선택했을 때, DetailsScreen으로 화면 전환하도록 할 것입니다. 그와 동시에 DetailsScreen에 Todo를 전달할 것입니다.

사용자의 탭 동작을 감지하기 위해, ListTile 위젯에 onTap 콜백을 작성할 것입니다. onTap 콜백 내에서 다시 한 번 Navigator.push 메서드를 사용할 것입니다.

ListView.builder(
  itemCount: todos.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(todos[index].title),
      // 사용자가 ListTile을 선택하면, DetailScreen으로 이동합니다.
      // DetailScreen을 생성할 뿐만 아니라, 현재 todo를 같이 전달해야
      // 한다는 것을 명심하세요.
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => DetailScreen(todo: todos[index]),
          ),
        );
      },
    );
  },
);

완성된 예제

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

class Todo {
  final String title;
  final String description;

  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 {
  final List<Todo> todos;

  TodosScreen({Key key, @required this.todos}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Todos'),
      ),
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(todos[index].title),
            // 사용자가 ListTile을 선택하면, DetailScreen으로 이동합니다.
            // DetailScreen을 생성할 뿐만 아니라, 현재 todo를 같이 전달해야
            // 한다는 것을 명심하세요.
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => DetailScreen(todo: todos[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  // Todo를 들고 있을 필드를 선언합니다.
  final Todo todo;

  // 생성자는 Todo를 인자로 받습니다.
  DetailScreen({Key key, @required this.todo}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // UI를 그리기 위해 Todo를 사용합니다.
    return Scaffold(
      appBar: AppBar(
        title: Text(todo.title),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Text(todo.description),
      ),
    );
  }
}

Passing Data Demo