Flutter와 Firebase로 Android iOS 둘 다 만들기 15 named router 사용하기

2 분 소요

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에 .만 치면 엄청난 메써드들이 나오는데 로그인 전환은 이정도면 충분할 것 같습니다.

영상

댓글남기기