티스토리 뷰

반응형

새로운 화면으로 이동할 때 데이터를 전달하는 경우가 종종 있습니다. 예를 들어, 사용자가 항목을 탭할 때 해당 항목에 대한 정보를 새 화면에 전달할 수 있습니다.

 

기억하세요: 화면은 단순히 위젯입니다. 이 예제에서는 할 일 목록을 생성하고, 할 일을 탭하면 해당 할 일에 대한 정보를 표시하는 새 화면(위젯)으로 이동합니다.

 

이 문서는 다음 단계를 사용합니다:

  1. 할 일 클래스를 정의합니다.
  2. 할 일 목록을 표시합니다.
  3. 할 일 정보를 표시할 수 있는 세부 화면을 만듭니다.
  4. 데이터와 함께 세부 화면으로 이동합니다.

 

 

 

1. 할 일 클래스 정의하기

먼저, 할 일을 간단하게 표현할 방법이 필요합니다. 이 예제에서는 제목과 설명 두 가지 데이터를 포함하는 클래스를 만듭니다.

class Todo {
  final String title;
  final String description;

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

 

 

 

2. 할 일 목록 생성하기

두 번째로, 할 일 목록을 표시합니다. 이 예제에서는 20개의 할 일을 생성하고 ListView를 사용하여 이를 표시합니다.

 

할 일 목록 생성

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

 

ListView를 사용하여 할 일 목록 표시

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

여기까지 잘 진행되었다면, 20개의 할 일을 생성하고 ListView에 표시될 것입니다.

 

 

 

3. 할 일 목록을 표시할 화면 생성하기

이 작업을 위해 StatelessWidget을 생성합니다. 이를 TodosScreen이라고 부르겠습니다. 이 페이지(화면)의 내용은 런타임 동안 변경되지 않으므로 TodosScreen 위젯 내에 할 일 목록을 필요로 합니다.

 

build() 메서드에서 반환할 위젯의 본문으로 ListView.builder를 전달합니다. 이렇게 하면 화면에 목록이 렌더링 됩니다.

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'),
      ),
      // `ListView.builder`를 전달합니다.
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(todos[index].title),
          );
        },
      ),
    );
  }
}

Flutter의 기본 스타일링을 사용하면, 나중에 하고 싶은 작업에 대해 걱정할 필요 없이 바로 시작할 수 있습니다!

 

 

 

4. 할 일 정보를 표시할 세부 화면 생성하기

이제 두 번째 화면을 만듭니다. 화면의 제목은 할 일의 제목을 포함하고, 화면의 본문은 할 일의 설명을 보여줍니다.

 

세부 화면은 일반 StatelessWidget이므로 세부 화면을 생성 시에 Todo를 입력하도록 요구합니다. 그런 다음 주어진 Todo를 사용하여 UI를 빌드합니다.

class DetailScreen extends StatelessWidget {
  // 생성자에서 `Todo`를 요구합니다.
  const DetailScreen({super.key, required this.todo});

  // `Todo`를 보관할 필드를 선언합니다.
  final Todo todo;

  @override
  Widget build(BuildContext context) {
    // `Todo`를 사용하여 UI를 생성합니다.
    return Scaffold(
      appBar: AppBar(
        title: Text(todo.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Text(todo.description),
      ),
    );
  }
}

 

 

 

5. 데이터와 함께 세부 화면으로 이동하기

DetailScreen이 준비되었으므로, 이제 네비게이션을 수행할 준비가 되었습니다. 이 예제에서는 사용자가 할 일 목록에서 항목을 탭할 때 DetailScreen으로 이동하고, TodoDetailScreen에 전달합니다.

 

TodosScreen에서 사용자의 탭을 캡처하려면 ListTile 위젯의 onTap() 콜백을 작성합니다. onTap() 콜백 내에서 Navigator.push() 메서드를 사용합니다.

body: ListView.builder(
  itemCount: todos.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(todos[index].title),
      // 사용자가 ListTile을 탭하면 DetailScreen으로 이동합니다.
      // 현재 todo를 전달합니다.
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => DetailScreen(todo: todos[index]),
          ),
        );
      },
    );
  },
)

 

완성 코드

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),
            // 사용자가 ListTile을 누르면, 상세 화면으로 이동한다.
            // 상세 화면을 만들 뿐만 아니라 현재 할 일을 전달한다.
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => DetailScreen(todo: todos[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  // 생성자는 할 일(Todo)을 필요로 한다.
  const DetailScreen({super.key, required this.todo});

  // Todo를 가지는 필드를 선언한다.
  final Todo todo;

  @override
  Widget build(BuildContext context) {
    // UI를 만들기 위해서 Todo를 사용한다.
    return Scaffold(
      appBar: AppBar(
        title: Text(todo.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Text(todo.description),
      ),
    );
  }
}

 

 

 

 

RouteSettings를 사용하여 인수 전달하기

위에서 사용한 1, 2 단계를 동일하게 사용합니다.

 

인수를 추출하여 표시하는 세부 화면 생성하기

다음으로, Todo에서 제목과 설명을 추출하여 표시하는 세부 화면을 만듭니다. Todo에 접근하려면 ModalRoute.of() 메서드를 사용합니다. 이 메서드는 인수가 있는 현재 라우트를 반환합니다.

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

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

    // `Todo`를 사용하여 UI를 생성합니다.
    return Scaffold(
      appBar: AppBar(
        title: Text(todo.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Text(todo.description),
      ),
    );
  }
}

 

인수를 전달하여 세부 화면으로 내비게이션 하기

마지막으로, 사용자가 ListTile 위젯을 탭할 때 Navigator.push()를 사용하여 DetailScreen으로 이동합니다. 인수를 RouteSettings의 일부로 전달합니다. DetailScreen은 RouteSettings로 전달된 인수를 사용합니다.

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) => const DetailScreen(),
            // 인수를 RouteSettings의 일부로 전달합니다.
            // DetailScreen은 이러한 설정에서 인수를 읽습니다.
            settings: RouteSettings(
              arguments: todos[index],
            ),
          ),
        );
      },
    );
  },
)

 

완성 코드

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),
            // 사용자가 ListTile을 탭하면 DetailScreen으로 이동합니다.
            // DetailScreen을 생성할 뿐만 아니라 현재 todo를
            // 해당 화면으로 전달합니다.
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const DetailScreen(),
                  // 인수를 RouteSettings의 일부로 전달합니다.
                  // DetailScreen은 이러한 설정에서 인수를 읽습니다.
                  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;

    // Todo를 사용하여 UI를 생성합니다.
    return Scaffold(
      appBar: AppBar(
        title: Text(todo.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Text(todo.description),
      ),
    );
  }
}
반응형
댓글
공지사항