
Flutter에서 현재 페이지를 변경하는 방식은 크게 두가지. push, pop과 같은 페이지의 stack을 쌓는 방법(이하, stack방식)과, switch와 같은 조건문을 사용해 조건에 따라 현재 페이지를 다시 build하는 방법(이하, switch방식) 두가지가 있다.

stack 방식은 Navigator에 Route를 쌓는방식이다.
때문에 페이지 전환 애니메이션도 페이지를 한장씩 쌓아올리거나 빼내는 방식이다.
// page1 페이지로 이동하는 함수.
// Navigator에 현재 페이지의 context와 Route(page1)을 push해 다음페이지로 이동한다.
Navigator.push(
context,
MaterialPageRoute(builder: (context) => page1()),
);
// 현재 페이지를 닫고, 이전페이지로 이동하는 함수.
// Navigator에 쌓인 현재 페이지를 Pop해 이전페이지로 돌아간다.
Navigator.pop(context);
stack에 페이지를 쌓는 방식이기 때문에 페이지를 이동한다고 해서 페이지가 사라지지 않는다. 페이지가 stack에 그대로 남아 자원을 소모하고있기 때문에, 너무 많은 페이지를 stack에 쌓는다면 앱의 속도가 점점 느려진다. 페이지가 종료된다면 stack에서도 소멸되 더이상 자원을 소모하지 않는다.

// # 예제 소스 코드
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: StackHome(),
);
}
}
// 페이지의 내용이 바뀌는것이 아니기 때문에 StatelessWidget를 사용한다.
class StackHome extends StatelessWidget {
const StackHome({Key key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Center(
child: RaisedButton(
// RaisedButton를 클릭했을 경우 실행되는 익명함수
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page1(),
),
);
},
child: Text("Push Page1"),
),
),
);
}
}
class Page1 extends StatelessWidget {
const Page1({Key key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page 1"),
),
body: Center(
child: Column(
// 자식을 세로로 배치하는 Column의 정렬방식을 center로 설정.
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page2(),
),
);
},
child: Text("Push Page2"),
),
RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("Pop"),
),
],
),
),
);
}
}
class Page2 extends StatelessWidget {
const Page2({Key key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page 2"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("Pop"),
),
),
);
}
}
switch 방식은 조건문을 사용해 조건에 따라 해당 페이지 전체 혹은 일부를 다시 build하는 방식이다.

SwitchHome에서 NavigationBar를 클릭할 때마다 페이지가 다시 build되기 때문에 페이지가 변경되더라도 한 페이지의 자원만 소모된다. 페이지가 소멸되어 데이터도 남지 않는다.

// # 예제 소스 코드
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: SwitchHome(),
);
}
}
// stack방식과는 달리 페이지의 내용이 바뀌기 때문에 StatefulWidget를 사용한다.
class SwitchHome extends StatefulWidget {
const SwitchHome({Key key}) : super(key: key);
_SwitchHomeState createState() => _SwitchHomeState();
}
class _SwitchHomeState extends State<SwitchHome> {
// NavigationBar에서 선택된 아이템의 번호를 담을 int 선언
int pageIdx = 0;
Widget build(BuildContext context) {
// pageIdx에 따라 Widget을 return할 switch문 메서드
Widget sCase() {
switch (pageIdx) {
case 0:
return SwitchPage1();
break;
case 1:
return SwitchPage2();
break;
case 2:
return SwitchPage3();
break;
default:
return Container();
break;
}
}
return Scaffold(
// AppBar는 각 페이지마다 바뀌어야 하니 여기에는 추가하지 않는다.
// body는 위의 switch문에서 return될 Widget을 받는다.
body: sCase(),
// bottom에 위치할 NavigationBar를 추가한다.
bottomNavigationBar: BottomNavigationBar(
// NavigationBar를 클릭했을때 나타낼 애니메이션종류
type: BottomNavigationBarType.fixed,
// NavigationBar의 배경색
backgroundColor: const Color(0xffffffff),
// NavigationBar의 그림자 크기
elevation: 10,
// 선택된 아이템의 색깔 (black)
selectedItemColor: Colors.black,
// 선택된 아이템의 Icon Theme. Size만 50으로 변경해준다.
selectedIconTheme: IconThemeData(size: 50),
// 선택된 아이템의 폰트사이즈
selectedFontSize: 15,
// 선택 안된 아이템의 색깔 (black, 투명도 60%)
unselectedItemColor: Colors.black.withOpacity(.60),
// 선택 안된 아이템의 폰트사이즈
unselectedFontSize: 15,
// 현재 선택된 Index
currentIndex: pageIdx,
// 아이템을 클릭할 경우 클릭한 아이템의 번호(index)를 pageIdx에 대입하고 setState()
onTap: (int index) {
setState(() {
pageIdx = index;
});
},
items: [
BottomNavigationBarItem(
label: "1번",
icon: Icon(Icons.one_k),
),
BottomNavigationBarItem(
label: "2번",
icon: Icon(Icons.two_k),
),
BottomNavigationBarItem(
label: "3번",
icon: Icon(Icons.three_k),
),
],
),
);
}
}
class SwitchPage1 extends StatelessWidget {
const SwitchPage1({Key key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
// Home에 AppBar가 없기 때문에 각 페이지에 맞는 AppBar추가
appBar: AppBar(
title: Text("switchPage 1"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 가시성을 위해 페이지별로 100*100의 색깔이 다른 Container를 넣어준다.
Container(
width: 100,
height: 100,
color: Colors.red,
),
Text("Page 1"),
],
),
),
);
}
}
class SwitchPage2 extends StatelessWidget {
const SwitchPage2({Key key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("switchPage 2"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 100,
height: 100,
color: Colors.orange,
),
Text("Page 2"),
],
),
),
);
}
}
class SwitchPage3 extends StatelessWidget {
const SwitchPage3({Key key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("switchPage 3"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 100,
height: 100,
color: Colors.green,
),
Text("Page 3"),
],
),
),
);
}
}