Route의 개념 이해하기
"Mobile apps typically reveal their contents via full-screen elements called 'Screens' or 'pages' in Flutter"
단순하게 설명하자면 핸드폰에서 보여지는 하나의 화면 혹은 페이지라고 이해하면 된다.
Route는 반드시 MaterialApp widget 아래에 child로 생성되어 있어야 한다.
Multi Page 이동을 하기 위해서 반드시 필요한 속성 (MaterialApp widget 아래에서)
routes: multi page 이동 시에 이동할 페이지들의 이름을 지정하고 출력하는 역할을 한다.
routes = const <String, WidgetBuilder>{} 로, Map 이라는 자료구조가 쓰인다.
Key : Value 로 사전처럼 매칭이 되는 구조.
즉, routes 에서는 Key가 String이 되고, Value가 WidgetBuilder가 되는 것이다.
String을 부르면, WidgetBuilder가 호출되는 식.
initialRoute: multi page 이동을 할 때에 화면에 제일 처음 출력되는 route를 불러오는 역할을 한다. (home과 같은 역할)
따라서, multi page 이동을 할 때에는 home 대신에 initialRoute를 사용한다. (home과 같이 사용하면 에러 발생)
Navigator의 개념 이해하기
"The navigator manages a stack of Route objects and provides methods for managing the stack,
like Navigator.push and Navigator.pop."
플러터 공식문서에도 나와있듯이 Navigator를 이해하기 위해서는 stack에 대한 이해가 필요하다.
stack은 간단하게 자료 데이터들이 들어오는 데로, 책들이 아래에서부터 쌓이면서 올라가듯이 아래에서부터 차곡차곡 쌓는 구조를 말한다.
push method: 자료를 밀어넣는 것으로, 데이터를 추가하는 method이다.
pop method: 자료를 빼는 것으로, 데이터를 삭제하는 method이다.
이러한 stack의 매커니즘이 그대로 Navigator에도 적용된다고 생각하면 된다.
FirstPage widget에서 SecondPage widget으로 이동한다고 했을 때 자료구조 상, FirstPage widget이 사라지고 SecondPage widget이 그 자리를 대신해서 보여주는 것이 아니라는 것을 기억해야 한다.
stack 자료구조처럼 FirstPage widget 위로 SecondPage widget이 쌓이게 되는 것이다.
Navigator.push(context, MaterialPageRoute((...)));
Q1. 왜 푸시할때 context가 파라미터로 필요한 것일까?
위에서 말했듯이 FirstPage widget 위로 SecondPage widget을 쌓아올리기 위해서는 FirstPage widget의 정확한 위치를 필요로 하기 때문이다.
Q2. 왜 굳이 푸시를 할 때마다 MaterialPageRoute의 빌더를 통해서 context를 할당받아야 하는 것일까?
일종의 안전장치로, 에러가 발생하는 것을 방지할 수 있다.
MaterialPageRoute widget과 context
return Center(
child: ElevatedButton(
child: Text("Go to the second page"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
),
);
멀티 페이지 이동 기능 구현
// main의 build 내부
return MaterialApp(
title: 'MyApp',
theme: ThemeData(
primaryColor: Colors.blue,
),
initialRoute: '/',
routes: {
'/': (context) => ScreenA(),
'/b': (context) => ScreenB(),
'/c': (context) => ScreenC(),
},
);
// ScreenA widget
return Scaffold(
appBar: AppBar(
title: Text("ScreenA"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/b');
},
child: Text("Go to ScreenB"),
style: ElevatedButton.styleFrom(
primary: Colors.red,
),
),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/c');
},
child: Text("Go to ScreenC"),
style: ElevatedButton.styleFrom(
primary: Colors.red,
),
),
],
),
),
);
여기서 중요한 점은, initialRoute와 routes는 서로 없으면 안되는 속성들이며, routes에서 지정해준 name을 통해서 이동한다는 점이다.
onPressed: () {
Navigator.pushNamed(context, '/b');
},
참고
코딩셰프 유튜브: https://youtu.be/rX2RZr6y8yM