Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
05-17 00:00
관리 메뉴

nomad-programmer

[Flutter] Navigation 본문

Programming/Flutter

[Flutter] Navigation

scii 2020. 10. 9. 18:15

새로운 화면으로 전환하거나 이전 화면으로 돌아가는 것을 네비게이션이라고 한다. 

새로운 화면으로 이동

새로운 화면을 띄우거나 이전 화면으로 돌아가는 방법을 이용해 두 화면을 내비게이션 하는 앱을 만들어보자.

// main.dart

import 'package:flutter/material.dart';
import 'package:test2/first_page.dart';

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

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

파일을 나눠 FirstPage 클래스와 SecondPage 클래스를 작성하자.

// first_page.dart

import 'package:flutter/material.dart';
import 'package:test2/second_page.dart';
import 'package:test2/person.dart';

// 첫 페이지
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('First'),
      ),
      body: new RaisedButton(
        onPressed: () async {
          final Person person = new Person('김연아', 31);
          final Person result = await Navigator.push(
            context,
            new MaterialPageRoute(
              builder: (BuildContext context) => new SecondPage(person: person),
            ),
          );
          print(result.name);
        },
        child: new Text('다음 페이지로'),
      ),
    );
  }
}

push로 새로운 화면 호출

FirstPage에서 SecondPage로 전환하려면 Navigator 클래스의 push() 메소드를 사용한다. 기본적인 사용 방법은 다음과 같다.

Navigator.push( 
  context, MaterialPageRoute(builder: (BuildContext context) => [이동할 페이지]),
);

첫 번째 인수로 context가 필요하고 두 번째 인수로 MaterialPageRoute 인스턴스가 필요하다. 이 클래스는 머터리얼 디자인으로 작성된 페이지 사이에 화면 전환을 할 때 사용된다. 
이 클래스의 builder 프로퍼티에 이동할 페이지를 나타내는 함수를 작성한다. 예를 들면 다음과 같은 람다 함수를 전달할 수 있다. 입력 매개 변수인 BuildContext 타입은 타입 추론에 의해 생략이 가능하다.

(context) => SecondPage()

Navigator.push() 메소드의 두 번째 인수로 사용된 MaterialPageRoute 클래스는 안드로이드와 iOS 각 플랫폼에 맞는 화면 전환을 지원해준다. builder 프로퍼티에는 BuildContext 인스턴스를 인수로 받고 이동할 화면의 클래스 인스턴스를 반환하는 함수를 작성한다. 


// second_page.dart

import 'package:flutter/material.dart';
import 'package:test2/person.dart';

// 두 번째 페이지
class SecondPage extends StatelessWidget {
  final Person person;

  SecondPage({@required this.person});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second'),
      ),
      body: new RaisedButton(
        onPressed: () {
          person.name = '신세경';
          Navigator.pop(context, person);
        },
        child: new Text('이전 페이지로'),
      ),
    );
  }
}

pop으로 이전 화면 이동

Navigator.push() 메소드는 새로운 화면이 표시되어도 이전 화면은 메모리에 남게 된다. 이때 Navigator.pop() 메소드로 현재 화면을 종료하고 이전 화면으로 돌아갈 수 있다.


// person.dart

class Person {
  String name;
  int age;

  Person(this.name, this.age);
}

새로운 화면에 값 전달

새로운 화면을 표시하면서 데이터도 함께 전달할 수 있다. 위와 같이 Person 클래스가 있다고 해보자. SecondPage 클래스에서 Person 객체를 받을 수 있도록 한다.

@required 를 붙이면 필수 입력 인수를 나타낸다. SecondPage클래스의 생성자는 Person 객체를 반드시 받아야 한다.

이전 화면으로 데이터 돌려주기

Navigator.push() 메소드와 Navigator.pop() 메소드를 조금 수정하면 SecondPage 클래스에서 FirstPage 클래스로 데이터를 돌려줄 수 있다. 다음 코드는 ok라는 문자열을 이전 페이지에 돌려준다.

Navigator.pop(context, 'ok');

FirstPage 클래스가 SecondPage 클래스로부터 데이터를 돌려받으려면 push() 메소드를 다음과 같이 수정한다.

onPressed: () async {
  final Person person = new Person('김연아', 31);
  final result = await Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SecondPage(person: person)),
  );
  
  print(result);
},

push() 메소드는 Future 타입의 반환 타입을 가진다. Future는 미래에 값이 들러올 것을 나타내는 클래스이다.

Futre 값을 반환받으려면 다음 두 가지 조건을 충족해야 한다.

  1. await 키워드를 메서드 실행 앞에 추가한다.
  2. await 키워드를 사용하는 메소드의 인수와 함수 본문 사이에 async 키워드를 추가한다.

이러한 코드는 push() 메소드가 어떤 값을 반환할 때까지 기다리게 한다. 그리고 반환값을 기다리는 동안 앱이 멈추지 않는다. 나중에 값이 들어오면 그 값이 result에 담긴 후 비로소 print문이 실행된다.


routes를 활용한 내비게이션

페이지를 이동할 때마다 직접 이동할 페이지의 클래스명을 작성했다. 그러면 페이지를 이동할 때마다 매우 긴 코드를 작성해야 해서 불편하다. routes를 활용한 내비게이션을 사용하면 좀 더 간결하고 체계적인 방법으로 내비게이션을 구성할 수 있다.

routes 정의

routes는 MaterialApp 클래스의 routes 프로퍼티에 다음과 같은 형태로 정의할 수 있다.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FirstPage(),
      routes: {
        '/first': (context) => FirstPage(),
        '/second': (context) => SecondPage(),
      },
    );
  }
}

routes 프로퍼티에 Map 형태로 문자열과 목적지 인스턴스를 작성하면 된다.

'/first'는 FirstPage 클래스로, '/second'/는 SecondPage 클래스로 연결되도록 정의했다. 여기서 맨 앞 슬래시(/) 기호를 사용한 이유는 페이지 구조를 /first/a/b 와 같은 형식으로 구조화하기 쉽게 때문이며, 이러한 표현 방식을 사용할 것을 추천한다.

routes에 의한 화면 이동

이제 기존의 push() 메소드 대신 pushNamed() 메소드를 사용하여 화면 네비게이션을 실행시킬 수 있다.

FirstPage 클래스의 화면 이동 부분은 다음과 같이 수정할 수 있다.

onPressed() async {
  final result = await Navigator.pushNamed(context, '/second');
},
Comments