Coaspe

Flutter - Navigator class 본문

Flutter/API

Flutter - Navigator class

Coaspe 2023. 2. 17. 13:59

Stack discipline을 따르는 자식 위젯들의 Set을 관리하는 위젯입니다.

 

많은 앱들은 Overlay를 사용하여 논리적 히스토리를 디스플레이하기 위해 위젯 계층의 최상위 주변에 navigator를 가지고 있으며, 오래된 페이지 위에 가장 최근에 방문한 페이지를 시각적으로 디스플레이합니다. 이런 패턴을 사용하는 것은 navigator가 overlay를 사용하여 한 페이지에서 다른 페이지로 시각적 트렌지션을 가능하게 합니다. 비슷하게, 현재 페이지에 다이얼로그 위젯을 표시하기 위해 navigator를 사용할 수 있습니다.

 

Using the Navigator API

모바일 앱은 보통 "screen", "pages"로 불리는 full-screen을 통해 컨텐츠를 보여줍니다. Flutter에서 이런 요소들을 routes라고 부르고 Navigator 위젯으로 관리합니다. Navigator는 Route 객체의 스택을 관리하고 스택을 관리하는 2가지 방법을 제공합니다. Declarative API (선언형 API)Navigator.pagesimperative API (명령형 API)인 Navigator.pushNavigator.pop가 존재합니다.

 

앱의 UI가 스택의 이전 요소로 navigate back 할 수 있어야 하는 스택의 패러다임과 잘 맞는다면, routes와 Navigator를 사용하는 것이 적절합니다. Android 같은 특정 플랫폼에서, 시스템 UI가 앱의 스택의 이전 routes로 돌아갈 수 있는 back 버튼을 제공합니다. 이런 build-in 네비게이션 메커니즘이 없는 플랫폼에서는, AppBar(보통 Scaffold.appBar 프로퍼티로 사용됩니다.)가 유저의 네비게이션을 위한 back 버튼을 자동으로 제공합니다.

 

Using the Pages API

Navigator는 제공된 Navigator.pagesRoutes의 스택으로 변환합니다. Navigator.pages를 변경하면 Routes 스택에 대한 업데이트가 트리거됩니다. Navigator는 자신의 Navigator.pages의 새로운 구성을 매치하기 위해 routes를 업데이트합니다. 이 API를 사용하기 위해, Page 서브클래스를 생성하고 Navigator.pages를 위한 Pages의 리스트를 정의해도 됩니다. 팝이 발생하는 경우 입력 페이지를 제대로 정리하려면 Navigator.onPopPage 콜백도 필요합니다.

 

Navigator는 routes가 스크린 트렌지션을 어떻게 in, out 할지 정하기 위해 DefaultTransitionDelegate를 디폴트로 사용합니다. 이것을 커스터마이즈하고 싶다면, TransitionDelegate 서브클래스를 정의하고 Navigator.transitionDelegate로 넘겨주세요.

 

Displaying a full-screen route

Navigator를 직접적으로 생성할 수 있지만, WidgetsApp이나 MaterialApp에 의해 생성되는 Router가 생성한 navigator를 사용하는 게 가장 일반적입니다. Navigator.of를 사용해 navigator를 참조할 수 있습니다.

 

MaterialApp을 사용하는 것이 가장 간단한 설정 방법입니다. MaterialApp의 home은 Navigator의 스택의 가장 밑 route가 됩니다. 다음은 app을 런치할 때 볼 수있는 코드입니다.

void main() {
  runApp(MaterialApp(home: MyAppHome()));
}

스택에 새로운 route를 푸시하고 싶다면 MaterialPageRoute를 스크린에 표시하고 싶은 위젯들을 포함하는 빌더 함수와 함께 생성하세요. 다음의 코드가 그 예입니다:

Navigator.push(context, MaterialPageRoute<void>(
  builder: (BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('My Page')),
      body: Center(
        child: TextButton(
          child: Text('POP'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  },
));

Route는 자식 위젯 대신 빌더 함수로 자신의 위젯을 정의합니다. 빌더 함수를 사용하는 이유는 route가 푸시되고 팝 될 때에 따른 context에서 built, rebuilt 되기 때문입니다.

 

보이는 것과 같이, 새로운 route는 Navigator의 pop 메소드를 사용하여 앱의 home page를 가져오며 팝될 수 있습니다.

Navigator.pop(context);

Scaffold가 자동으로 Appbar에 '뒤로' 버튼을 추가하기 때문에 일반적으로 Scaffold가 있는 route에서 Navigator를 팝하는 위젯을 제공할 필요가 없습니다. back 버튼을 누르면 Navigator.pop가 호출됩니다. Android에서 시스템 back 버튼을 누르는 것도 똑같이 작동합니다.

 

Using named navigator routes

종종 모바일 앱이 많은 수의 routes를 관리하고 그 routes들을 이름으로 참조하는 것은 좋은 방법입니다. 이름으로 routes하는 것은 경로 같은 구조를 가집니다.(예를 들어 '/a/b/c'). 앱의 home 페이지 route는 디폴트로 '/'로 설정됩니다.

 

MaterialApp의 routes는 route의 이름과 해당 route의 빌더 함수로 구성된 Map<String, WidgetBuilder>로 이루어집니다. MaterialApp는 자신의 navigator의 onGenerateRoute 콜백을 위한 value로 해당 Map을 사용할 수 있습니다.

void main() {
  runApp(MaterialApp(
    home: MyAppHome(), // becomes the route named '/'
    routes: <String, WidgetBuilder> {
      '/a': (BuildContext context) => MyPage(title: 'page A'),
      '/b': (BuildContext context) => MyPage(title: 'page B'),
      '/c': (BuildContext context) => MyPage(title: 'page C'),
    },
  ));
}

Name으로 route를 푸시하고 싶다면 다음과 같이 시도하세요.

Navigator.pushNamed(context, '/b');

 

Routes can return a value

Route가 유저가 원하는 값을 얻기 위해 푸시 된다면, 그 값은 pop 메소드의 result 파라미터로 반환됩니다.

Route를 푸시한 메소드는 Future를 반환합니다. 그 Future는 route가 팝 될 때, resolve되고 Future의 값은 pop 메소드의 result 파라미터 입니다.

예를 들어 어떤 명령에 대해 유저가  'OK' text 를 누를 것인지 물어보고 싶다면, 다음과 같이 Navigator.push의 결과를 await하면 됩니다:

bool value = await Navigator.push(context, MaterialPageRoute<bool>(
  builder: (BuildContext context) {
    return Center(
      child: GestureDetector(
        child: Text('OK'),
        onTap: () { Navigator.pop(context, true); }
      ),
    );
  }
));

만약 유저가 "OK"를 누르면 결과값은 true가 됩니다. Scaffold의 back 버튼을 누르는 것 처럼 route를 나와버리면 해당 값은 null이 됩니다.

 

Route가 값을 반환하기 위해 사용될 때, route의 type 파라미터는 pop 메소드의 result의 type과 매치되어야합니다. 그게 바로 우리가 MaterialPageRoute<void> or just MaterialPageRoute 대신에 MaterialPageRoute<bool>를 사용하는 이유입니다. (사실 타입을 특정하지 않아도 괜찮습니다.)

 

Popup routes

Routes가 꼭 전체 스크린을 다 가려야하는 것은 아닙니다. PopupRoutes는 현재 스크린이 뒤에 비쳐보일 수 있게 부분적으로 불투명하게 해주는 ModalRoute.barrierColor로 스크린을 처리할 수 있습니다. Popup routes는 들어오는 입력을 뒤로가지 못하게 막으므로 "modal" 입니다.

 

showDialog, showMenu, 그리고 showModalBottomSheet와 같이 Popup routes를 생성하고 보여주는 함수들도 있습니다. 이 함수들은 푸시된 route의 Future를 반환합니다. 함수의 콜러는 route가 팝될 때 액션을 취하거나, route의 값을 얻기 위해 반환 값을 await 할 수 있습니다.

 

PopupMenuButton DropdownButton 같이 popup routes를 생성하는 위젯도 있습니다. 이 위젯들은 내부적으로 PopupRoute의 서브클래스를 생성하고 그 서브클래스들을 show하고 dismiss하기 위해 Navigator의 push, pop 메소드를 사용합니다.

 

Custom routes

PopupRoute, ModalRoute, or PageRoute 같은 위젯 라이브러리 route 클래스들 중 하나의 서브 클래스를 만들어 route나 route의 modal barrier의 색, 동작 및 route의 다른 측면을 표시하는 데 사용되는 애니메이션 트렌지션을 제어할 수 있습니다.

 

PageRouteBuilder 클래스는 callbacks의 개념으로 커스텀 route를 생성합니다. 다음은 route가 나타나고 사라질 때 자식을 회전하고 페이드하는 예제입니다. 이 route는 opaque: false로 설정하기 때문에 popup route 처럼 화면 전체를 방해하지 않습니다:

Navigator.push(context, PageRouteBuilder(
  opaque: false,
  pageBuilder: (BuildContext context, _, __) {
    return Center(child: Text('My PageRoute'));
  },
  transitionsBuilder: (___, Animation<double> animation, ____, Widget child) {
    return FadeTransition(
      opacity: animation,
      child: RotationTransition(
        turns: Tween<double>(begin: 0.5, end: 1.0).animate(animation),
        child: child,
      ),
    );
  }
));

위의 Page route는 "page"와 "transition" 두 부분으로 build 됩니다. page는 transitionBuilder 함수로 전달된 자식의 후손이 됩니다. page는 animation 파라미터에 의존하지 않기 때문에, 보통 오직 한 번만 build 됩니다. transition은 Duration 동안 매 프레임 build 됩니다.

 

이하 작성 중...

'Flutter > API' 카테고리의 다른 글

Flutter - Stack class  (0) 2023.02.17
Flutter - findAncestorStateOfType method  (0) 2023.02.17
Flutter - AnimatedWidget  (0) 2023.02.17
Flutter - ImplicitlyAnimatedWidget  (0) 2023.02.17
Flutter - Tween<T extends Object?>  (0) 2023.02.17
Comments