조용한 담장

Flutter : Navigator 본문

Flutter

Flutter : Navigator

iosroid 2019. 10. 17. 12:10

Flutter : Navigator

앱 화면 간 이동을 구현할 때 사용한다. 또는 특정 위젯 간의 이동이 될 수도 있다.

navigator 를 이용한 예제를 만들어 보자.

예제코드

기본 코드 구조는 아래와 같다.

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
);
}
}
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigator demo Home'),
),
body: ListView(
children: <Widget>[
],
),
);
}
}
class Page1 extends StatelessWidget {}
class Page2 extends StatelessWidget {}
class Page3 extends StatelessWidget {}
class Page4 extends StatelessWidget {}

앱의 각각 다른 화면을 page로 구분하여 각각을 위젯으로 구성해 볼 것이다.

App's home page

Homepage 에서 page1, page2, page3, page4 로 이동할 수 있는 버튼을 가진 화면을 구현해보자.

Navigator

Navigator({Key key, String initialRoute, @required RouteFactory onGenerateRoute, RouteFactory onUnknownRoute, List observers: const [] })

 

A widget that manages a set of child widgets with a stack discipline.

 

화면 또는 페이지가 되는 자식 위젯들을 관리하며 자식 위젯간의 이동을 가능하도록 해준다.

이동할 대상을 route 라 하여 스택 방식으로 관리되고 정보전달 도 가능하게 한다.

Route class

Route({RouteSettings settings })

 

An abstraction for an entry managed by a Navigator.

 

Navigator 에 의해 이동하게 될 앱의 화면, 페이지를 나타내는 정보들을 가지고 있다.

Navigator class 가 Route class 의 정보를 이용해서 지정된 route 로 이동하고 돌아오는 동작을 할수 있게 된다.

간단하게 Navigator 가 사용가능 한 MaterialApp class 를 이용해본다.

MaterialApp 에는 앱 에서 사용 할 모든 route 를 가진 table 를 지정해야 한다.

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
initialRoute: '/',
routes: {
'/': (BuildContext context) => HomePage(),
'/page1': (BuildContext context) => Page1(),
'/page4': (BuildContext context) => Page4(),
},
);
}
}
view raw routes.dart hosted with ❤ by GitHub

initialRoute 는 앱의 첫 화면을 가리키는 route 이다. '/'로 이름을 지정하였다.

routes(Map<String, WidgetBuilder>) 에 initialRoute 를 포함하여 이름이 '/', '/page1', '/page4' 인 route 3개를 포함시켰다.

Navigator 는 routes 에서 일치하는 이름을 찾아 route 를 사용하게 된다.

Navigator.pushNamed

Future<T> pushNamed <T extends Object>(
  BuildContext context,
  String routeName, {
    Object arguments
})

이름에 해당하는 route 로 이동한다. route 의 이름을 인자(routeName)로 전달한다.

실제 하는 동작은 route 이름을 Navigator 의 onGenerateRoute 콜백에 전달하여 route 를 생성한 후 Navigator 에 push 한다.

argumensts 는 이동하려는 route 로 전달할 수 있는 값이다.

class _HomePageState extends State<HomePage> {
// ...
body: ListView(
children: <Widget>[
Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('page1 named'),
color: Colors.blue[400],
onPressed: () {
Navigator.pushNamed(context, '/page1');
},
),
),
],
),
// ...
}

Page1 위젯이 생성되어 화면에 그려질 것이다.

Navigator.push

Future<T> push <T extends Object>(
  BuildContext context,
  Route<T> route
)

해당하는 route 로 이동한다. route 를 직접 인자(route)로 전달 한다.

routes 목록에 있는 'page1' 과 같지만 이름을 쓰지 않고 route 를 직접 전달하여 동작한다.

새로운 route 가 push 되고 이전 route 로 돌아갈때는 pop 을 한다.

Navigator.pop

bool pop <T extends Object>(
  BuildContext context, [
    T result
])

context 상에서 가장 가까운 이전 route 를 찾아 이동한다.

result 는 돌아가는 route 에 전달할 수 있는 값이다.

Example of Navigator push and pop

class _HomePageState extends State<HomePage> {
// ...
body: ListView(
children: <Widget>[
Container(
height: 100.0,
color: Colors.white,
alignment: Alignment.center,
child: Text('Home'),
),
Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('page1'),
color: Colors.blue,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Page1()),
);
},
),
),
],
),
// ...
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigator demo page1'),
),
body: Center(
child: FlatButton(
color: Colors.blueGrey,
child: Text('Back'),
onPressed: () {
Navigator.pop(context);
},
)
),
);
}
}

'page1' 버튼을 누르면 MaterialPageRoute() 로 page1 route 를 생성하여 push() 한다.

Page1 에서 'Back' 버튼을 누르면 pop() 을 호출하여 이전 페이지로 돌아간다.

Return data

이전 route 로 돌아갈 때 pop() 의 result 를 통해 데이터를 전달할 수 있다.

Page2 에서 home page 로 이동하기 위해 'Back' 버튼을 누른 시간을 전달하여 home page 에 표시 해본다.

class _HomePageState extends State<HomePage> {
var visitTime;
@override
Widget build(BuildContext context) {
// ...
body: ListView(
children: <Widget>[
Container(
height: 100.0,
color: Colors.white,
alignment: Alignment.center,
child: _homeText(),
),
Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('page2'),
color: Colors.blue[300],
onPressed: () {
_navigateFromPage2(context);
},
),
),
],
),
// ...
}
Widget _homeText() {
if(visitTime != null) {
var text = Text('Home\nfrom page2 at\n' + visitTime);
visitTime = null;
return text;
} else {
return Text('Home');
}
}
_navigateFromPage2(BuildContext context) async {
visitTime = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => Page2()),
);
print('pop result: ' + visitTime);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigator demo page2'),
),
body: Center(
child: FlatButton(
color: Colors.blueGrey,
child: Text('Back'),
onPressed: () {
Navigator.pop(context, DateTime.now().toString());
},
)
),
);
}
}

Pass data

현재 route 에서 이동하려는 route 에 필요한 data를 전달해 줄 수 있다.

Page3 는 이전 페이지에서 visitTime 을 받아 화면에 보여준다.

home page 에서 Page3 로 이동하는 시간을 argument 로 전달해 Page3 의 visitTime 값이 지정된다.

Page3 constructor 에 visitTime 을 추가한다.

Page3({Key key, @required this.visitTime})
class _HomePageState extends State<HomePage> {
// ...
body: ListView(
children: <Widget>[
Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('page3'),
color: Colors.blue[200],
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page3(
visitTime: DateTime.now().toString()
)
),
);
},
),
),
],
),
// ...
}
class Page3 extends StatelessWidget {
final visitTime;
Page3({Key key, @required this.visitTime}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigator demo page3'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('visit time from home:\n$visitTime'),
Center(
child: FlatButton(
color: Colors.blueGrey,
child: Text('Back'),
onPressed: () {
Navigator.pop(context);
},
)
),
],
)
);
}
}

PushNamed arguments

PushNamed 의 arguments 를 통해 데이터를 전달한다.

Home page 에서 Page4 로 이동 시 Map object 로 'message' 와 'time' 값을 전달한여 Page4 에서 화면에 출력하는 예제이다.

argument 는 ModalRoute.of 을 이용해 얻는다.

class _HomePageState extends State<HomePage> {
// ...
body: ListView(
children: <Widget>[
Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('page4'),
color: Colors.blue[100],
onPressed: () {
Navigator.pushNamed(
context,
'/page4',
arguments: <String, String>{
'message': 'left home at',
'time' : DateTime.now().toString(),
},
);
},
),
),
],
),
// ...
}
class Page4 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final Map<String,String> args = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text('Navigator demo page4'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(args['message']),
Text(args['time']),
Center(
child: FlatButton(
color: Colors.blueGrey,
child: Text('Back'),
onPressed: () {
Navigator.pop(context);
},
)
),
],
)
);
}
}

Reference

Flutter Documentation

'Flutter' 카테고리의 다른 글

Flutter : Draggable  (0) 2019.10.28
Flutter : SelectableText  (0) 2019.10.21
Flutter : Text Widgets  (0) 2019.10.14
Flutter : State management (Provider)  (1) 2019.10.11
Flutter : declarative UI  (0) 2019.10.08
Comments