티스토리 뷰

반응형

때때로 새로운 화면에서 이전 화면에 데이터를 반환하고 싶을 때가 있습니다.

 

예를 들어, 새 화면에서 사용자가 두 가지 옵션 중 하나를 선택할 수 있고, 사용자가 옵션을 선택하면 이전 화면에 그 선택을 알려주어 해당 정보를 기반으로 작업을 수행하게 됩니다.

 

다음 단계로 Navigator.pop() 메서드를 사용하여 이를 수행할 수 있습니다:

  1. 홈 화면 정의
  2. 선택 화면을 여는 버튼 추가
  3. 두 개의 버튼이 있는 선택 화면 표시
  4. 버튼이 눌리면 선택 화면 닫기
  5. 홈 화면에 선택 사항을 스낵바로 표시하기

 

 

 

1. 홈 화면 정의

홈 화면에는 버튼이 표시됩니다. 이 버튼을 탭하면 선택 화면이 시작됩니다.

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Returning Data Demo'),
      ),
      // 다음 단계에서 SelectionButton 위젯을 생성합니다.
      body: const Center(
        child: SelectionButton(),
      ),
    );
  }
}

 

 

 

2. 선택 화면을 여는 버튼 추가

이제 SelectionButton을 생성합니다. 이 버튼은 다음을 수행합니다:

  • 탭하면 SelectionScreen을 시작합니다.
  • SelectionScreen이 결과를 반환할 때까지 대기합니다.
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!'),
    );
  }

  Future<void> _navigateAndDisplaySelection(BuildContext context) async {
    // Navigator.push는 SelectionScreen에서 Navigator.pop을 호출한 후에
    // 완료되는 Future를 반환합니다.
    final result = await Navigator.push(
      context,
      // 다음 단계에서 SelectionScreen을 생성합니다.
      MaterialPageRoute(builder: (context) => const SelectionScreen()),
    );
  }
}

 

 

 

3. 두 개의 버튼이 있는 선택 화면 표시

이제 두 개의 버튼이 있는 선택 화면을 만듭니다. 사용자가 버튼을 탭하면 선택 화면이 닫히고 홈 화면에 어떤 버튼이 눌렸는지 반환합니다.

이 단계에서는 UI를 정의합니다. 다음 단계에서는 데이터를 반환하는 코드를 추가합니다.

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: [
            Padding(
              padding: const EdgeInsets.all(8),
              child: ElevatedButton(
                onPressed: () {
                  // "Yep"으로 팝업...
                },
                child: const Text('Yep!'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8),
              child: ElevatedButton(
                onPressed: () {
                  // "Nope"으로 팝업...
                },
                child: const Text('Nope.'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

 

 

 

4. 버튼이 눌리면 선택 화면 닫기

이제 두 버튼 모두의 onPressed() 콜백을 업데이트합니다. 첫 번째 화면에 데이터를 반환하려면 선택적 두 번째 인수로 result를 받아들이는 Navigator.pop() 메서드를 사용합니다. 어떤 결과든 SelectionButton의 Future로 반환됩니다.

 

Yep 버튼

ElevatedButton(
  onPressed: () {
    // 화면을 닫고 "Yep!"을 결과로 반환합니다.
    Navigator.pop(context, 'Yep!');
  },
  child: const Text('Yep!'),
)

 

Nope 버튼

ElevatedButton(
  onPressed: () {
    // 화면을 닫고 "Nope."을 결과로 반환합니다.
    Navigator.pop(context, 'Nope.');
  },
  child: const Text('Nope.'),
)

 

 

 

5. 홈 화면에 선택 사항을 스낵바로 표시하기

이제 선택 화면을 시작하고 결과를 대기하고 있으므로 반환된 정보를 처리해야 합니다.

이 경우, SelectionButton의 _navigateAndDisplaySelection() 메서드를 사용하여 결과를 표시하는 스낵바를 보여줍니다:

// SelectionScreen을 시작하고 Navigator.pop의 결과를
// 대기하는 메서드입니다.
Future<void> _navigateAndDisplaySelection(BuildContext context) async {
  // Navigator.push는 SelectionScreen에서 Navigator.pop을 호출한 후에
  // 완료되는 Future를 반환합니다.
  final result = await Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => const SelectionScreen()),
  );

  // StatefulWidget에서 BuildContext를 사용할 때는 비동기로 작동 후에는
  // mounted 속성을 확인해서 위젯이 화면에 보이는지 확인해야 한다.
  // mounted 속성이 false이면 위젯이 더 이상 화면에 표시되지 않음을 의미한다.
  if (!context.mounted) return;

  // SelectionScreen이 결과를 반환한 후, 이전 스낵바를 숨기고
  // 새로운 결과를 표시합니다.
  ScaffoldMessenger.of(context)
    ..removeCurrentSnackBar()
    ..showSnackBar(SnackBar(content: Text('$result')));
}

 

 

 

전체 코드

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!'),
    );
  }

  // SlectionScreen을 시작하고 Navigator.pop의 결과를 대기하는 메서드입니다.
  Future<void> _navigateAndDisplaySelection(BuildContext context) async {
    // Navigator.push는 SelectionScreen에서 Navigator.pop을 호출한 후에
    // 완료되는 Future를 반환합니다.
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => const SelectionScreen()),
    );

    // StatefulWidget에서 BuildContext를 사용할 때는 비동기로 작동 후에는
    // mounted 속성을 확인해서 위젯이 화면에 보이는지 확인해야 한다.
    // mounted 속성이 false이면 위젯이 더 이상 화면에 표시되지 않음을 의미한다.
    if (!context.mounted) return;

    // SelectionScreen이 결과를 반환한 후, 이전 스낵바를 숨기고
    // 새로운 결과를 표시합니다.
    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: () {
                  // 화면을 닫고 "Yep!"을 결과로 반환합니다.
                  Navigator.pop(context, 'Yep!');
                },
                child: const Text('Yep!'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8),
              child: ElevatedButton(
                onPressed: () {
                  // 화면을 닫고 "Nope."을 결과로 반환합니다.
                  Navigator.pop(context, 'Nope.');
                },
                child: const Text('Nope.'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

 

반응형
댓글
공지사항