꿈꾸는 시스템 디자이너

Flutter 강좌 - Pass arguments to a named route | 스크린(라우트)간 아규먼트 전달 본문

Development/Flutter

Flutter 강좌 - Pass arguments to a named route | 스크린(라우트)간 아규먼트 전달

독행소년 2019. 6. 24. 17:03

 

Flutter 강좌 목록 : https://here4you.tistory.com/120

 

개발할 앱에서 새로운 라우트를 호출할 때 아규먼트를 전달하는 경우가 있다. 예를 들어 라우트의 타이틀과 바디에 출력할 텍스트를 아규먼트로 전달하여 동적으로 구성하는 경우가 한 예이다.

소스코드는 다음과 같다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget{

  @override
  Widget build(BuildContext context) {

    return MaterialApp(

      title: 'Navigation with arguments', // 타이틀 설정
      home: HomeScreen(), // 첫번째 라우트로 HomeScreen 설정

      // 라우트 설정
      // ExtractArgumentsScreen의 라우트만 등록, PassArgumentsScreen은 등록안됨
      routes: {
        // '/extractArguments':(context)=>ExtractArgumentsScreen() 를 의미함
        ExtractArgumentsScreen.routeName:(context)=>ExtractArgumentsScreen()
      },

      /**
       * onGenerateRoute: 앱이 이름이 부여된 라우트를 네비게이팅할 때 호출됨. RouteSettings 가 전달됨
       * RouteSettings: 다음과 같은 구조를 가짐
       * const RouteSettings({
          String name,  // 라우터 이름
          bool isInitialRoute: false, // 초기 라우터인지 여부
          Object arguments  // 파라미터
          })

       * routes 테이블에 PassArgumentsScreen이 등록되지 않았지만 onGenerateRoute 함수에 의해 라우터 호출이 가능함
       */
      onGenerateRoute: (routeSettings){ // Navigator.pushNamed() 가 호출된 때 실행됨

        // 라우트 이름이 PassArgementScreen의 routeName과 같은 라우트가 생성될 수 있도록 함
        if(routeSettings.name == PassArgumentsScreen.routeName){
          // 라우트세팅에서 파라미터 추출
          final ScreenArguments args = routeSettings.arguments;

          return MaterialPageRoute(
              builder: (context){
                // 추출한 파라미터를 PassArgumentScreen의 아규먼트로 직접 전달하면서 라우트 생성 후 반환
                return PassArgumentsScreen(
                  title: args.title,
                  message: args.message,
                );
              }
          );
        }
      },
    );
  }
}

// 앱 실행시 출력되는 라우트
class HomeScreen extends StatelessWidget{

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('Home Screen'),
      ),
      body: Center( // 가운데
        child: Column(  // 컬룸 추가
          mainAxisAlignment: MainAxisAlignment.center, // 자식들은 가운데 정렬
          children: <Widget>[


            // 첫번째 자식. 파라미터를 명시적으로 전달하는 방식으로 라우트 호출
            RaisedButton(
              child: Text('Navigate to screen that extracts arguments'),
              onPressed: (){
                Navigator.pushNamed(  //(context,routeName,arguments)
                    context,
                    ExtractArgumentsScreen.routeName,
                    arguments: ScreenArguments(
                        'Extract Arguments Screen',
                        'This message is extracted in the build method.'
                    )
                );
              },
            ),

            // 두번째 자식
            RaisedButton(
              child: Text('Navigate to a named that accpts arguments'),
              onPressed: (){
                Navigator.pushNamed(  //(context,routeName,arguments)
                    context,
                    PassArgumentsScreen.routeName,
                    arguments: ScreenArguments(
                        'Accept Arguments Screen',
                        'This message is extracted in the onGenerateRoute function.'
                    )
                );
              },
            )
          ],
        ),
      ),
    );
  }
}

// 넘겨받은 context에서 아규먼트를 추철하여 라우트를 동적 구성하는 클래스
class ExtractArgumentsScreen extends StatelessWidget{
  // 라우트의 이름 설정
  static const routeName = '/extractArguments';

  @override
  Widget build(BuildContext context) {

    // context로부터 settings.arguments값을 추출하여 arg로 저장
    final ScreenArguments args = ModalRoute.of(context).settings.arguments;

    // 추출한 아규먼트로 Scaffold를 구성하여 반환
    return Scaffold(
      appBar: AppBar(
        title: Text(args.title),
      ),
      body: Center(
        child: Text(args.message),
      ),
    );
  }

}

// 전달받은 아규먼트를 이용하여 라우트를 동적 구성하는 클래스
class PassArgumentsScreen extends StatelessWidget{
  // 라우트의 이름 설정
  static const routeName = '/passArguments';

  final String title; // 라우트의 타이틀로 활용
  final String message; // 라우트의 바디로 활용

  // 생성자. 라우트 생성시 전달한 파라미터를 아규먼트로 넘겨받아 필드에 저장
  const PassArgumentsScreen({
    Key key,
    @required this.title,
    @required this.message
  }):super(key:key);

  @override
  Widget build(BuildContext context) {

    // 전달받은 아규먼트로 Scaffold를 구성하여 반환
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Text(message),
      ),
    );
  }
}

// 라우트 생성시 전달할 아규먼트 클래스
class ScreenArguments{
  // 아규먼트의 타이틀과 메시지. 생성자에 의해서만 초기화되고 변경할 수 없음
  final String title;
  final String message;

  // 생성자
  ScreenArguments(this.title, this.message);
}

 

메인 함수에서 MyApp을 호출하고 있으며, MyApp에서는 HomeScreen을 home으로 설정하여 앱을 실행한다. 지난 강의에서 소개한 routes 테이블을 이용해서 라우트에 이름을 부여해서 호출할 수 있도록 하는 구조를 가진다.

onGenerateRoute 항목은 이름이 부여된 라우트가 새롭게 네이게이팅 될 때 호출되는 항목이다.

우선 HomeScreen 클래스부터 확인해본다.

Scaffold의 body에서는 컬럼을 이용해서 두개의 RaisedButton을 구성하고 버튼이 클릭되면 해당 라우트가 적재되어 출력되도록 하는 코드이다. 두개의 RaiseButton의 구성을 동일하며 차이점은 pushNamed 함수의 두번째 파라미터의 라우트의 이름만 다르다는 것이다.

Navigator.pushName() 함수는 context, routeName, arguments 순으로 파라미터를 입력할 수 있는데 각 버튼의 두번째 항목인 routeName만 다르게 구현되어 있다. 각 routeName은 해당하는 라우트 클래스에 필드로 정의된 이름을 이용하고 있다.

첫번째 네임드 라우트인 ExtractArgumentScreen은 수신한 아규먼트에서 title과 text를 추출하여 라우트를 동적 구현하는 방식으로 구현되어 있다. ModalRoute.of(context).settings.arguments 를 통해서 컨텐스트 내부에 저장된 아규먼트를 추철해서 라우트를 구성하는 방식이다.

두번째 네임드 라우트인 PassArgumentsScreen는 생성자를 통해 직접 아규먼트를 받아서 라우트의 화면을 동적 구성하는 방식이다.

 

다시 MaterialApp의 구현부분으로 올라가보자.

routes 항목에는 ExtractArgumentsScreen만이 등록되어 있다. 그러므로 PassArgumentsScreen은 등록되지 않아 실행할 수 없는 구조로 보인다.

하지만 그 하단에 onGenerateRoute 항목에 의해서 PassArgumentsScreen 라우터가 정상적으로 실행될 수 있게 된다.

onGenerateRoute 항목에서는 네임드 라우트가 실행될 때마다 콜백이 실행되며, RouteSettings 데이터를 수신할 수 있게 된다. RouteSettings 데이터는 다음과 같은 구조를 가진다.

const RouteSettings({
          String name,  // 라우터 이름
          bool isInitialRoute: false, // 초기 라우터인지 여부
          Object arguments  // 파라미터
          })

name 항목을 통해 실행할 라우트의 이름을 확인할 수 있으며 그 이름이 PassArgumentsScreen의 routeName 필드의 값과 공일하면 MaterialPageRoute 함수를 통해 PassArgumentsScreen 라우트를 생성하여 반환하게 된다. 이 때 PassArgumentsScreen의 생성자로 아규먼트를 직접 전달하게 된다.

실행화면은 다음과 같다.

 

본 강좌는 Flutter 공식 사이트의 문서를 참조하여 작성되었습니다.

https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments

 


Flutter Code Examples 강좌를 추천합니다.

  • 제 블로그에서 Flutter Code Examples 프로젝트를 시작합니다.
  • Flutter의 다양한 예제를 소스코드와 실행화면으로 제공합니다.
  • 또한 모든 예제는 Flutter Code Examples 앱을 통해 테스트 가능합니다.

Flutter Code Examples 강좌로 메뉴로 이동

Flutter Code Examples 강좌 목록 페이지로 이동

Flutter Code Examples 앱 설치 | Google Play Store로 이동

 

Flutter Code Examples - Google Play 앱

Are you a beginner at Flutter? Check out the various features of Flutter through the demo. Source code for all demos is also provided.

play.google.com

Comments