티스토리 뷰

Flutter 애플리케이션을 개발할 때, 화면 간 데이터 전달과 반환은 매우 중요한 요소입니다. 특히, 사용자가 특정 작업을 완료한 후 결과 데이터를 이전 화면으로 반환하는 경우, Navigatorpop 메서드를 활용한 데이터 반환 방법은 핵심적인 스킬입니다. 이번 포스트에서는 Flutter에서 데이터를 반환하며 화면을 전환하는 과정을 자세히 살펴보겠습니다.

참고. Return data from a screen

데이터를 반환하며 화면 전환이 필요한 상황

Flutter 애플리케이션 개발 중 다음과 같은 상황에서 데이터를 반환하는 기능이 필요합니다:

  1. 사용자 입력을 전달해야 하는 경우:
    예를 들어, 새 화면에서 폼을 작성한 뒤 그 결과를 이전 화면으로 반환.
  2. 작업 완료 결과를 전달하는 경우:
    예를 들어, 파일 업로드 성공 여부나 데이터 처리 결과를 전달.
  3. 선택된 옵션 반환:
    예를 들어, 사용자가 리스트에서 항목을 선택하면 그 값을 이전 화면으로 전달.

데이터를 반환하는 기본 구조

1. Navigator.pop 메서드 활용

Flutter에서는 Navigator.pop(context, result)를 사용하여 결과 데이터를 반환할 수 있습니다. 여기서 result는 반환하려는 데이터로, 문자열, 객체, 또는 리스트 등 어떤 데이터 타입도 가능합니다.

2. await 키워드로 반환 값 수신

Navigator.push 메서드를 통해 새 화면으로 이동한 뒤, 이전 화면으로 돌아올 때 반환 값을 await 키워드를 사용해 받을 수 있습니다.

단계별 구현 가이드

Step 1: 새 화면 생성 및 데이터 반환

아래는 새 화면에서 데이터를 반환하는 코드 예제입니다:

import 'package:flutter/material.dart';

class SelectionScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('항목 선택'),
      ),
      body: ListView(
        children: [
          ListTile(
            title: Text('Option 1'),
            onTap: () {
              Navigator.pop(context, 'Option 1');
            },
          ),
          ListTile(
            title: Text('Option 2'),
            onTap: () {
              Navigator.pop(context, 'Option 2');
            },
          ),
        ],
      ),
    );
  }
}

Step 2: 호출 화면에서 데이터 수신

이제 이전 화면에서 Navigator.push를 통해 새 화면으로 이동하고, 반환 값을 받아 처리하는 코드를 작성합니다:

import 'package:flutter/material.dart';
import 'selection_screen.dart'; // 새 화면 파일

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('홈 화면'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            final result = await Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SelectionScreen()),
            );

            // 반환된 값 처리
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('선택한 항목: $result')),
            );
          },
          child: Text('항목 선택 화면으로 이동'),
        ),
      ),
    );
  }
}

반환 데이터에 대한 활용 팁

  1. 에러 핸들링 추가:
    Navigator.pop을 호출하지 않거나 사용자가 뒤로가기를 누를 경우, 반환 값이 null일 수 있으므로 이를 처리하는 로직을 추가해야 합니다.
  2. 복잡한 데이터 구조 사용:
    단순 문자열뿐만 아니라, JSON이나 객체와 같은 복잡한 데이터 구조를 반환하도록 설계할 수 있습니다.
  3. Reusable Widget 설계:
    반환 데이터 처리 로직을 별도의 위젯이나 유틸리티 함수로 추상화하여 재사용성을 높입니다.

샘플 프로젝트 구조

  • main.dart:
    앱의 진입점. HomeScreen에서 SelectionScreen을 호출합니다.
  • selection_screen.dart:
    데이터를 반환하는 화면.
  • 유틸리티 파일:
    데이터 반환 로직을 모듈화하여 재사용 가능한 함수로 정의.

결론

Flutter에서 데이터를 반환하며 화면을 전환하는 기능은 효율적인 화면 간 데이터 관리를 위해 반드시 익혀야 할 기술입니다. Navigator.popawait의 조합은 단순하면서도 강력한 도구로, 다양한 애플리케이션 시나리오에서 활용 가능합니다. 이번 가이드를 통해 데이터를 반환하며 화면을 전환하는 방법을 실무에 적용해 보세요!

 

import 'package:flutter/material.dart';

void main() {
  runApp(
    const MaterialApp(
      title: 'Returning Data',
      home: HomeScreen(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Returning Data Demo'),
      ),
      body: const Center(
        child: SelectionButton(),
      ),
    );
  }
}

class SelectionButton extends StatefulWidget {
  const SelectionButton({super.key});

  @override
  State<SelectionButton> createState() => _SelectionButtonState();
}

class _SelectionButtonState extends State<SelectionButton> {
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        _navigateAndDisplaySelection(context);
      },
      child: const Text('Pick an option, any option!'),
    );
  }

  // A method that launches the SelectionScreen and awaits the result from
  // Navigator.pop.
  Future<void> _navigateAndDisplaySelection(BuildContext context) async {
    // Navigator.push returns a Future that completes after calling
    // Navigator.pop on the Selection Screen.
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => const SelectionScreen()),
    );

    // When a BuildContext is used from a StatefulWidget, the mounted property
    // must be checked after an asynchronous gap.
    if (!context.mounted) return;

    // After the Selection Screen returns a result, hide any previous snackbars
    // and show the new result.
    ScaffoldMessenger.of(context)
      ..removeCurrentSnackBar()
      ..showSnackBar(SnackBar(content: Text('$result')));
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Pick an option'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8),
              child: ElevatedButton(
                onPressed: () {
                  // Close the screen and return "Yep!" as the result.
                  Navigator.pop(context, 'Yep!');
                },
                child: const Text('Yep!'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8),
              child: ElevatedButton(
                onPressed: () {
                  // Close the screen and return "Nope." as the result.
                  Navigator.pop(context, 'Nope.');
                },
                child: const Text('Nope.'),
              ),
            )
          ],
        ),
      ),
    );
  }
}