본문 바로가기

Mobile/Flutter

[Flutter] 페이지 이동 - 네비게이터(Navigator) 이해하기

728x90
반응형

페이지 이동 기능을 구현하기 위해서는 먼저 Route와 Navigator의 개념을 이해해야 한다.

 

Route?

단순히 스마트폰에서 하나의 페이지, 화면. Scaffold 위젯을 리턴하는 모든 커스텀 위젯 하나하나가 route이다.

 

Navigator?

모든 앱페이지들(Routes)을 관리하며 stack 자료구조 형식으로 route 객체들을 관리한다. 이 stack 자료구조를 관리하기 위해서 Navigator.pushNavigator.pop이라는 메서드를 제공한다.

 

 

<전체 코드>

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Page'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Go to the Second page'),
          onPressed: () {
            Navigator.push(context,
                MaterialPageRoute(builder: (BuildContext context) {
              return SecondPage();
            }));
          },
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext ctx) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Page'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Go to the First page'),
          onPressed: () {
            Navigator.pop(ctx);
          },
        ),
      ),
    );
  }
}

 

Second Page는 First Page를 제거하고 그 자리로 들어가는 것이 아니라 자료구조 상 FirstPage 위로 쌓여진다. 그래서 Second Page는 화면에 보여지던 First Page 위에 놓여서 First Page를 가리고 자신이 보여지게 되는 것이다.

 

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Page'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Go to the Second page'),
          onPressed: () {
            Navigator.push(context,
                MaterialPageRoute(builder: (BuildContext context) {
              return SecondPage();
            }));
          },
        ),
      ),
    );
  }
}

First page에 있는 onPressed 함수에서 push 메서드를 사용해서 Second page로 이동하는 기능을 구현했다.

 

Navigator.push(context, route)

: context가 가지고 있는 위젯 트리 상의 위치 정보에 근거해서 현재 화면 상에 보여지는 페이지가 어떤 페이지인지 확인하고 이 페이지 위에 push 함수가 이동하기를 원하는 새로운 route를 쌓아올린다.

 

왜 push 함수를 불러올 때마다 MaterialPageRoute를 사용하고 이 안에서 builder를 통해 context를 할당받아야 할까?

route는 push 메서드를 통해 다양한 곳에서 호출되며 그 때마다 생성되고 또 필요에 따라서 재생성되는 과정을 거치게 된다. 단순히 Child 속성을 사용해서 계속 Child 위젯 형식으로 route를 추가할 수도 있을 것이다. 그러나 언제 Route의 호출이 일어나는가에 따라서 Route가 build하는 과정 중에 다른 context를 사용하게 될 수도 있고 자칫 잘못된 context를 전달해서 Route에 호출해 에러를 발생시킬 수도 있다. builder을 사용하면 이런 에러를 미연에 방지할 수 있고 builder에서 제공한 context를 사용할 필요가 없으면 사용하지 않아도 된다.

 

Android, iOS에서 제공하는 기본 페이지 이동 애니메이션이 있다.

- Android: 위로 올라오면서 fade in, 페이지에서 나갈 때는 아래로 내려가면서 fadeout

- iOS: 좌우로 화면이 움직이면서 페이지 이동

MaterialPageRoute를 사용하면 기본적으로 Android에서 제공하는 페이지 이동 애니메이션을 사용한다.

 

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext ctx) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Page'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Go to the First page'),
          onPressed: () {
            Navigator.pop(ctx);
          },
        ),
      ),
    );
  }
}

Second page에 있는 onPressed 함수에서는 pop 메서드를 사용해서 First page로 돌아가는 기능을 구현했다.

 

Navigator.pop(context)

Navigator은 stack 자료구조를 사용하기 때문에 First page 위에 있는 Second page를 없애주기만 하면 된다. 

앱바를 생성하면 자동으로 뒤로가기 화살표 버튼을 만들어주기 때문에 pop 메서드를 구현할 필요가 없다. 물론 앱바를 생성하지 않으면 뒤로가기 기능을 위해서 pop 메서드를 구현해야 한다.

728x90
반응형