새로운 강의는 이제 https://memi.dev 에서 진행합니다.
memi가 Vue & Firebase로 직접 만든 새로운 사이트를 소개합니다.
Flutter와 Firebase로 Android iOS 둘 다 만들기 15 named router 사용하기
Material class의 route를 이용해서 페이지 전환해봅니다.
개요
로그인 전/후 페이지 처리는 항상 골머리 아픈 부분입니다.
다행하게도 플러터에도 웹사이트처럼 페이지 라우트를 해주는 방법이 있습니다.
참고: https://flutter-ko.dev/docs/cookbook#navigation
참고: https://medium.com/flutter-community/flutter-push-pop-push-1bb718b13c31
페이지 스택
페이지 이동이란 개념보다는 쌓는다는 표현이 적절합니다.
그래서 push, pop 2가지 개념만 잘 이해하면 됩니다.
이해를 돕기위해 간단한 예제를 만들어봅니다.
로그인 페이지와 메인페이지 이동하기
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.indigo,
),
initialRoute: '/',
routes: {
'/': (context) => Home(),
'/signin': (context) => SignIn()
},
);
}
}
class Home extends StatelessWidget {
const Home({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('home')),
body: RaisedButton(
child: Text('signin'),
onPressed: () {
Navigator.pushNamed(context, '/signin');
},
),
);
}
}
class SignIn extends StatelessWidget {
const SignIn({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('signin'),),
body: RaisedButton(
child: Text('home'),
onPressed: () {
Navigator.pushNamed(context, '/');
},
),
);
}
}
initialRoute로 초기페이지를 지정해도 되고 home: Home()으로 지정해도 됩니다.
페이지마다 이름을 지었기 때문에 이제 pushNamed라는 메써드로 이동이 가능합니다.
이 예제를 실행해보면 2페이지가 잘 바뀌긴 하는데 상단에 백버튼(<-)이 생깁니다.
이것은 스캐폴드 앱바가 자동으로 만들어준 것이며 스택에 쌓였기 때문에 누른만큼 백버튼을 누르면 없어지는 것을 알 수 있습니다.
stack | click |
---|---|
/ | 3 |
/signin | 2 |
/ | 2 |
/signin | 1 |
/ | 1 |
home과 sign 은 쌓여서는 안되기 때문에 이럴 때 교체를 할 수 있습니다.
Navigator.pushReplacementNamed(context, '/');
Navigator.pushReplacementNamed(context, '/sign');
회원가입과 로그인 토글하기
home과 signin은 스택의 맨 아래에 있어야 되기 때문에 replace를 하는 것이고
signup(회원가입)은 signin 위의 스택에 올려놓는 것이 적당합니다.
routes: {
'/': (context) => Home(),
'/signin': (context) => SignIn(),
'/signup': (context) => SignUp(), // signup 추가
},
class SignIn extends StatelessWidget {
const SignIn({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('signin'),),
body: Column(
children: <Widget>[
RaisedButton(
child: Text('home'),
onPressed: () {
Navigator.pushReplacementNamed(context, '/');
},
),
RaisedButton(
child: Text('signup'),
onPressed: () {
Navigator.pushNamed(context, '/signup');
},
),
],
),
);
}
}
class SignUp extends StatelessWidget {
const SignUp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('signup'),),
body: Column(
children: <Widget>[
RaisedButton(
child: Text('signin'),
onPressed: () {
Navigator.pop(context);
},
),
RaisedButton(
child: Text('home'),
onPressed: () {
Navigator.pushReplacementNamed(context, '/');
},
),
],
),
);
}
}
signup 페이지를 라우터에 추가하고 signin, up이 토글되게 만들었습니다.
signin페이지에서 signup을 누르면 해당페이지로 이동하고 백버튼이 생기는 것을 알 수 있습니다.
signup페이지에서 백버튼을 누르거나 signin 버튼을 누르는 것은 동일한 효과를 나타내는 것을 알 수 있습니다.
백버튼의 효과가 결국 pop이기 때문입니다.
하지만 여기서 문제가 발생합니다.
회원가입을 마치자마자 홈페이지로 가는 것을 만든 것인데.. 홈페이지에 백버튼이 있기 때문입니다.
이 상황은
before | after |
---|---|
signup | home |
signin | signin |
이런 상황입니다.
즉 signup페이지가 home으로 replace 되었기 때문에 home에서 백버튼을 누르면 signin페이지로 가게 됩니다.
그래서 이런 코드를 써봅니다.
Navigator.popAndPushNamed(context, '/');
하나를 지우고 새로운 페이지를 띄우기 때문에 pushReplacementNamed과 같습니다.
다만 페이지 전환효과가 다른 차이가 있습니다.
이럴 때 사용해야할 메써드가 바로 새로운 페이지를 띄우고 아래 스택의 모든 것을 지우는 방법입니다.
Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false);
마치며
그밖에도 Navigator에 .만 치면 엄청난 메써드들이 나오는데 로그인 전환은 이정도면 충분할 것 같습니다.
댓글남기기