순한맛 22 네비게이터 이해하기
- Route의 개념
Flutter에서 Route 개념 : 스마트폰에서 보여지는 하나의 화면(Screen) 또는 페이지(Page)를 뜻함.
- Navigator의 정의
: 모든 App Page들을 관리하며, App Pages의 데이터들을 관리하기 위해서 Stack이라는 차곡차곡 쌓는 자료구조 형식으로 Route 개체들을 관리함.
또한, Stack 자료구조를 활용하기 위해 push, pop method 제공함.
(* stack 자료구조
FILO 구조 : First In Last Out. 선입 후출.
들어오는건 순서대로, 나가는건 가장 마지막 것부터
들어올때 push(), 내보낼때 pop() )
First Page에서 Second Page로 이동했을 때, 실제로는 First Page 위에 Second Page가 스택 구조로 쌓여서 First Page가 보이지 않는 것.
- Navigator.push()
body: Center(
child: ElevatedButton(
child: Text('Go to the Second Page'),
onPressed: () {
//MaterialPageRoute는 Builder를 argument를 가지고 있음.
//builder는 reqiured이기에 반드시 argument를 불러와야함
Navigator.push(context, MaterialPageRoute(builder:(BuildContext context){
return SecondPage();
}
)); //또는,
// Navigator.push(context, MaterialPageRoute(
// builder: (context) => SecondPage()));
},
)
),
1) push할때, context가 필요한 이유
: context가 가지고 있는 위젯트리 위치에 근거해서 현재 화면 위에 push 함수가 이동하길 원하는 새로운 route를 쌓아 올려하기 때문
2) push 함수 불러올때마다 MaterialPageRoute 사용하고 이 안에서 builder 통해서 context를 Flutter에 의해서 할당받아야 하는 이유 (= - MaterialPageRoute 위젯과 context)
: statelesswidget 만들때, 플러터가 항상 build 함수를 가져다주고 BuildContext도 자동으로 할당해줬음.
Route는 Push 함수를 통해서 다양한 곳에서 호출되어 생성되고, 필요에 의해 또 재생성 되기도 함. Route를 잘못 생성하거나 잘못 호출할 수도 있는데 Builder를 이용하면 이를 미리 방지할 수 있고 필요하지 않다면 사용하지 않아도 됨.
MaterialPageRoute에서 Builder는 안전장치와 같음
- Navigator.pop()
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext ctx) {
return Scaffold(
appBar: AppBar(
title: Text('Second page'),
),
body: Center(
child: ElevatedButton(
child: Text('Go to the First Page'),
onPressed: () {
Navigator.pop(ctx); //자신의 context만 Navigator에 전달
},
)
),
);
}
}
- push 전, push 후 Widget Tree 차이


(+주절 나는 왜 위치가 바뀐걸까...?...)
전체 코드
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'First app',
theme: ThemeData(
primarySwatch: Colors.blue
),
home: FirstPage(),
);
}
}
//앱페이지를 구성하기 위해 Scaffold를 리턴하는 모든 위젯을 하나하나의 라우터라 생각하면 된다.
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First page'),
),
body: Center(
child: ElevatedButton(
child: Text('Go to the Second Page'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder:(BuildContext context){
return SecondPage();
}
));
// 또는 Navigator.push(context, MaterialPageRoute(
// builder: (context) => SecondPage()));
},
)
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext ctx) {
return Scaffold(
appBar: AppBar(
title: Text('Second page'),
),
body: Center(
child: ElevatedButton(
child: Text('Go to the First Page'),
onPressed: () {
Navigator.pop(ctx); //자신의 context만 Navigator에 전달
},
)
),
);
}
}
순한맛 23 네비게이터(Navigator)와 푸시네임드 메소드(pushNamed Method)
- MaterialPageRoute에서 Builder는 안전장치와 같음
그래서 필요 없으면 안 써도 됨. _(underscore)로 표시
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (_) => SecondPage())); //필요없는 매개변수 표시할때 _ 이용
},

Scaffold를 이용해서 appbar를 설정하면 Flutter에서 자동으로 뒤로가기버튼 생성 > 굳이 pop 메소드 만들 필요 없음
- .dart를 여러개 만들어 좀더 복잡한 페이지 이동 구현
initialRoute
: 멀티페이지 이동 시, 화면에 가장 먼저 불러오는 Route 불러오는 역할.
= home argument와 똑같은 역할. 두개가 동시에 존재하면 에러 발생. 주의
routes = const <String:WidgetBuilder>{}
: 이동할 페이지들의 이름을 지정하고 생성하는 역할
<String.WidgetBuilder> = Map 자료형을 가지고 있음
- Map 자료구조
Key : Value
1대1 대응구조
바다 : Sea (예시로 사전)
key 값을 부르면 Value가 실행되는 구조
- 속성 설정 및 기능 구현
1. Flutter 첫 페이지 설정 📄 main.dart 📄
웹 페이지 초기 화면이 index.html로 지정되어 있는 것처럼 Flutter에서 첫 Route는 / (Slash)로 지정되어 있음
initialRoute: '/',
2. 모든 route argument 불러와서 key값 부여하고 실행시킬 value값 설정 📄 main.dart 📄
String 자료형 : WidgetBuilder (Builder 함수 생성)
routes: {
'/' : (context) => ScreenA(), // 키값인 슬래시가 불려지만 value값인 ScreenA가 build 되어야함
'/b' : (context) => ScreenB(),
'/c' : (context) => ScreenC(),
},
3. ScreenB, ScreenC 이동 구현 📄 ScreenA.dart 📄
pushenamed : push 함수와 기능을 동일하지만, 이동할 페이지마다 부여한 고유의 이름을 통해서 위젯을 빌드한 후, 푸쉬
children: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/b'); //ScreenB로 이동
},
child: Text('Go to ScreenB')),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/c'); //ScreenC로 이동
},
child: Text('Go to ScreenC'))
]
- 전체 코드
main.dart
import 'package:flutter/material.dart';
import 'package:push_named/ScreenA.dart';
import 'package:push_named/ScreenB.dart';
import 'package:push_named/ScreenC.dart';
void main() =>runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/' : (context) => ScreenA(), // 키값인 슬래시가 불려지만 value값인 ScreenA가 build 되어야함
'/b' : (context) => ScreenB(),
'/c' : (context) => ScreenC(),
},
);
}
}
ScreenA.dart
import 'package:flutter/material.dart';
class ScreenA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ScreenA'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // 정중앙 위치
children: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/b');
},
child: Text('Go to ScreenB')),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/c');
},
child: Text('Go to ScreenC'))
]),
));
}
}
ScreenB & C
import 'package:flutter/material.dart';
class ScreenB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ScreenB'), // ScreenC
),
body: Center(
child: Text(
'ScreenB', // ScreenC
style: TextStyle(
fontSize: 24.0
),
)
)
);
}
}

(+주절주절 나는 왜 자꾸 push 되는게 밑으로 내려갈까..... 근데 표현이 달라졌다고 생각하고 실행은 잘되니 넘어간다.)
'공부 > Flutter' 카테고리의 다른 글
| Flutter 스터디 10 Collection과 Generic (Generics 보충) (0) | 2023.01.30 |
|---|---|
| Flutter Navigator/context 퀴즈 (0) | 2023.01.30 |
| Flutter 스터디 8 Container Widget 되짚어보기, Column & Row Widget 되짚어보기 (0) | 2023.01.30 |
| Flutter 스터디 7 스낵바와 BuildContext, Builder 위젯 없이 스낵바 만들기와 토스트 메세지 (0) | 2023.01.26 |
| Flutter 스터디 6 BuildContext (0) | 2023.01.25 |