오늘 배울 것
오늘은 Flutter 에서 기본 제공하는 Navigator를 사용해 화면 간 이동 방법에 대해서 배워보겠습니다.
홈 → 입력 → 리스트 화면을 오가면서 Navigator 메서드(함수) push, pop, pushReplacement, popUntil 을 익혀봅시다.
Navigator 메서드 요약표
먼저 Navigator의 각 메서드에 대한 설명을 간략히 표로 정리하였습니다. 이를 바탕으로 실습을 진행하겠습니다.
메서드 | 설명 | 뒤로가기 | 사용 예 |
push() | 새 화면 추가 | O | Navigator.push(context, MaterialPageRoute(...)) |
pop() | 현재 화면 제거 | - | Navigator.pop(context) |
pushReplacement() | 현재 화면을 새로운 화면으로 교체 | ❌ | Navigator.pushReplacement(context, MaterialPageRoute(...)) |
popUntil() | 조건을 만족할 때까지 스택에서 화면 제거 | ❌ (중간 생략) | Navigator.popUntil(context, (route) => route.isFirst) |
실습 방법
각 화면에 Navigator 를 이용하여 화면 간 이동을 구현합니다.
화면을 모두 구현했다면 실제 버튼을 클릭하며 Navigator가 어떻게 동작하는지 살펴봅니다.
1. 앱 진입점
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Navigator 실습',
home: const HomeScreen(),
);
}
}
앱을 실행하면 홈 화면으로 HomeScreen 을 불러오도록 합니다.
2. 홈 화면에서 입력 화면으로 이동
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('홈')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const InputScreen()),
);
},
child: const Text('입력 화면으로 이동'),
),
ElevatedButton(
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const InputScreen()),
);
},
child: const Text('입력 화면으로 교체 이동'),
),
],
),
),
);
}
}
Navigator.push( ... ) 는 InputScreen 으로 새로운 화면을 쌓으며 이동합니다. 쌓으며 이동하기 때문에 화면이 바뀌더라도 HomeScreen 이 그대로 남아있기 때문에 뒤로 가기가 가능합니다.
이와 달리, Navigator.pushReplacement( ... ) 는 InputScreen 으로 현재 화면을 새로운 화면으로 교체하며 이동합니다. HomeScreen이 남아있지 않기 때문에 뒤로 가기가 불가능합니다.
HomeScreen의 Navigator를 도식화하면 다음과 같습니다.
*잠깐! MaterialPageRoute은 뭔가요?
MaterialPageRoute는 Flutter에서 새로운 화면으로 이동할 때 화면이 어떻게 전환될지를 정해주는 Route 객체 중 하나입니다. Navigator 메서드는 Route 객체를 인자로 받기 때문에 아래 3가지 중 하나를 써야 합니다.
- MaterialPageRoute: 안드로이드 스타일 전환
- CupertinoPageRoute: iOS 스타일 전환
- PageRouteBuilder: 직접 커스텀 전환 만들고 싶을 때
3. 입력 화면에서 리스트 화면으로 이동
class InputScreen extends StatefulWidget {
const InputScreen({super.key});
@override
State<InputScreen> createState() => _InputScreenState();
}
class _InputScreenState extends State<InputScreen> {
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('입력 화면')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(controller: _controller),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
final input = _controller.text;
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ListScreen(value: input),
),
);
},
child: const Text('리스트 화면으로 이동'),
),
ElevatedButton(
onPressed: () {
final input = _controller.text;
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => ListScreen(value: input),
),
);
},
child: const Text('리스트 화면으로 교체 이동'),
),
],
),
),
);
}
}
홈 화면에서 입력 화면으로 이동하는 것과 동일하게 Navigator.push( ... ) 와 Navigator.pushReplacement( ... ) 로 이동하도록 구현합니다.
HomeScreen과 InputScreen의 Navigator를 도식화하면 다음과 같습니다.
4. 리스트 화면에서 뒤로 가기
class ListScreen extends StatelessWidget {
final String value;
const ListScreen({super.key, required this.value});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('리스트 화면')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('입력값: $value', style: const TextStyle(fontSize: 24)),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.pop(context); // 한 단계 뒤로
},
child: const Text('뒤로가기'),
),
ElevatedButton(
onPressed: () {
Navigator.popUntil(context, (route) => route.isFirst);
},
child: const Text('홈으로 돌아가기'),
),
],
),
),
);
}
}
리스트 화면에서는 다시 이전 화면과 첫 화면으로 돌아가고자 합니다. Navigator.pop( ... ) 을 통해 이전 화면으로 돌아가고, Navigator.popUntil( ... ) 통해 홈 화면으로 돌아 갈 수 있습니다.
전체 코드의 Navigator 흐름을 도식화하면 다음과 같습니다.
단, 이 둘은 모두 이전의 화면들이 쌓여있을 경우에 가능합니다. 만약 pushReplacement 를 통해 화면을 교체 이동했다면 이전의 화면 스택이 없으므로 뒤로 돌아갈 수가 없어 동작을 하지 않거나 검은 화면으로 이동합니다.
실제 동작하는 앱을 통해서 확인해 보겠습니다.
아래 gif 영상은 push로 화면을 이동하고 한번 pop을 통해 뒤로 가기 후 다시 pushReplacement를 통해 화면을 교체하여 이동, 마지막에는 홈 화면으로 popUntil 하는 모습입니다.
입력 화면이 리스트 화면으로 교체되었음에도 popUntil 이 동작하는 이유는 직전 화면인 입력 화면은 스택에 쌓여있지 않지만 홈 화면은 스택에 쌓여있기 때문입니다. 이 경우에는 pop 또한 직전 화면인 입력 화면이 아니라 홈 화면으로 이동합니다.
아래 gif 영상은 pushReplacement로 화면을 이동한 후 홈으로 돌아가기 popUntil가 동작하지 않는 모습입니다. 그리고 pop으로 직전 화면으로 이동하려고 하면 쌓여있는 화면 스택이 없어 검은 화면으로 이동하게 됩니다.
이처럼 Navigator 의 각 메서드는 서로 역할이 다르기 때문에 사용자가 서비스를 원활히 이용할 수 있도록 화면 간 이동을 적절히 설계해주어야 합니다.
Recap
- push() → 새로운 화면을 쌓음 (뒤로 가기 가능)
- pop() → 한 단계 뒤로 돌아감
- pushReplacement() → 현재 화면을 교체 (뒤로가기 안 됨)
- popUntil() → 원하는 조건까지 한 번에 스택에서 제거
'Flutter 독학으로 기본기 익히기' 카테고리의 다른 글
07. 비동기 상태에 따라 UI를 바꾸는 FutureBuilder 알아보기 (0) | 2025.05.08 |
---|---|
06. Flutter 비동기 처리 Future, async/await 알아보기 (1) | 2025.05.07 |
04. Flutter 에서 자주 사용하는 레이아웃 위젯 (0) | 2025.05.03 |
03. 위젯 트리 구조, DevTools 로 Widget Tree 보는 방법 (0) | 2025.05.02 |
02. StatelessWidget과 StatefulWidget 비교하기 (0) | 2025.05.01 |