import 'package:flutter/material.dart';
import 'package:flutter_ver1/pages/jin_navigation/route_one_screen.dart';
class NavigationScreen extends StatefulWidget {
const NavigationScreen({super.key});
@override
State<NavigationScreen> createState() => _NavigationScreenState();
}
class _NavigationScreenState extends State<NavigationScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("NavigationScreen"),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const RouteOneScreen();
},
),
);
},
child: const Text("Push!"),
)
],
),
),
);
}
}
import 'package:flutter/material.dart';
class MainLayout extends StatelessWidget {
final String title;
final List<Widget> children;💡
const MainLayout({💡
super.key,
required this.title,
required this.children,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),💡
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: children,💡
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_ver1/pages/jin_navigation/layout/main_layout.dart';
import 'package:flutter_ver1/pages/jin_navigation/route_one_screen.dart';
class NavigationScreen extends StatefulWidget {
const NavigationScreen({super.key});
@override
State<NavigationScreen> createState() => _NavigationScreenState();
}
class _NavigationScreenState extends State<NavigationScreen> {
@override
Widget build(BuildContext context) {
return MainLayout( //MainLayout 가져와서 인자로 title, children넘겨줌
title: 'NavigationScreen',💡
children: [💡
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const RouteOneScreen();
},
),
);
},
child: const Text("Push!"),
)
],
);
}
}
Text(number.toString()),
class RouteOneScreen extends StatelessWidget {
final int number;💡
const RouteOneScreen({super.key, required this.number});💡
@override
Widget build(BuildContext context) {
return MainLayout(
title: 'RouteOneScreen',
children: [
Text(number.toString()),💡
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text("POP!"),
)
],
);
}
}
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const RouteOneScreen(number: 123);💡
},
),
);
},
child: const Text("Push!"),
)
ElevatedButton(
onPressed: () {
Navigator.of(context).pop(456);💡
},
child: const Text("POP!"),
)
ElevatedButton(
onPressed: () async {
final result = await Navigator.of(context).push(💡
MaterialPageRoute(
builder: (BuildContext context) {
return const RouteOneScreen(number: 123);
},
),
);
print(result);
},
child: const Text("Push!"),
)
RouteOneScreen에서 RouteTowScreen로
RouteOneScreen
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const RouteTowScreen();
},
settings: const RouteSettings(💡
arguments: 789,
),
),
);
},
child: const Text("Push!"),
)
RouteTowScreen는 ModalRoute()클래스를 변수에 담아줌 of(context)
를 붙여서 위젯트리에서 가장 가까운 ModalRoute를 가져옴 final argument = ModalRoute.of(context);
ModalRoute() : 풀스크린의 위젯의미
RouteTowScreen 스크린에서 가장 위젯 트리에 가까운 풀스크린 라우트는 그냥 RouteTowScreen이다.
RouteTowScreen여기서 값을 가져와야하는 거임 RouteOneScreen에서 settings안에 arguments를 넣어 놨기 때문에 다음 코드와 같이 값을 가져옴
final argument = ModalRoute.of(context)!.settings.arguments;
(특정상황에서 null이 있을수 있음 하지만 지금은 없기 때문에 null있을 수 없다는 의미의 !
를 입력해준다.)
Widget build(BuildContext context) {
final argument = ModalRoute.of(context)!.settings.arguments;💡
return Scaffold(
body: MainLayout(
title: 'RouteTowScreen',
children: [
Text(
'argument : ${argument.toString()}',💡 // 값 들어오는지 확인
textAlign: TextAlign.center,
),
ElevatedButton(
o
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/three', arguments: 901);
},
child: const Text('RouteThreeScreen'),
),
pushReplacement(newRoute)
- 일반 push랑 비슷
pushReplacementNamed(routeName)
- 일반 Named Routed랑 비슷
기존에는 NavigationScreen에서 RouteOneScreen push하고, RouteOneScreen에서 RouteThreeScreen push 하고 RouteTwoScreen에서 RouteThreeScreen push하면
Stack은[NavigationScreen(), RouteOneScreen(), RouteTwoScreen(), RouteThreeScreen()]
순서대로 오른쪽으로 push가되고 왼쪽부터 pop이된다.
하지만 아래 코드와 같이 pushReplacement
를 하거나 pushReplacementNamed
onPressed했을 때 RouteTwoScreen()를 Stack에서 지워버리기 때문에 RouteThreeScreen에서 pop을 했을 때 Stack에서 RouteOneScreen으로 이동된다.
Stack -[NavigationScreen(), RouteOneScreen(), RouteThreeScreen()]
ElevatedButton(
onPressed: () {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (BuildContext context) => const RouteThreeScreen()));
},
child: const Text("pushReplacement!"),
)
pushAndRemoveUntil(newRoute, (route) => false)
pushNamedAndRemoveUntil(routeName, (route) => false)
일반 라우트처럼 첫번째 인자에 MaterialPageRoute()를 넣어주고,(네임드일때는 경로이름)
두번째 인자인 (route) => false
에 조건별로 원하는 값을 넣어준다.
ElevatedButton(
onPressed: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) =>
const RouteThreeScreen()),
(route) => false);
},
child: const Text("pushAndRemoveUntil!"),
)
(route) => false
를 그대로 두고 RouteThreeScreen로 이동하면 RouteThreeScreen제외하고 라우트가 모두 지워진다.[RouteThreeScreen()]
(route) => route.settings.name == '/'
이런식으로 조건을 걸어줘서 name이 '/'
일때만 안지우고 나머지 라우트로 이동하면 다 지우게 할 수 있다.ElevatedButton(
onPressed: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) =>
const RouteThreeScreen()),
(route) => route.settings.name == '/');
},
child: const Text("pushAndRemoveUntil!"),
)
ElevatedButton(
onPressed: () {
Navigator.of(context).maybePop();
},
child: const Text("maybePop!"),
),
maybePop를 넣고 뒤에 어떤 페이지가 있는지 없는지 알 수 없을 때 canPop를 통해 print를 찍어서 존재여부를 알 수 있다.(다른 기능은 하지 않고 true, false만 찍힘)
더 이상 현재 Screen제외하고 Stack에 아무것도 없을
현재 Screen제외하고 뒤에 Stack에 다른 Screen이 있을 때
ElevatedButton(
onPressed: () {
print(Navigator.of(context).canPop());
},
child: const Text("conPop!"),
),
return PopScope(
canPop: true, //false인 경우 현재 경로가 pop되지 않도록 차단
onPopInvoked: (didPop) {
//do your logic here:
setStatusBarColor(
statusBarColorPrimary,
statusBarIconBrightness: Brightness.light,
);
finish(context);
},
child: Scaffold(/*other child and ui etc*/),
);