[Flutter]
Navigator는 앱 화면 간 이동을 구현할 때 사용한다.
Navigator는 스택 개념으로 작동을 한다. 즉 Last In First Out 특징을 갖고 있는데,
만약 first screen, second screen, third screen 3개의 화면이 존재할 때,
first screen - second screen - third screen으로 이동을 했다면
third screen - second screen - first screen 화면으로 나와야 한다는 의미이다.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => routeClass(),
),
);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => routeClass(),
),
);
Navigator.pop(context);
Navigator.of(context).pop();
위 두개의 코드로 Screen을 push, pop 할 수 있다.
아래의 간단한 예제를 살펴보자.
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
title: 'Navigator',
home: FirstScreen(),
),
);
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Go Second Screen'),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondScreen()));
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Go First Screen'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
위는 전체적인 코드다.. 아래를 보면서 코드를 이해해보자.
스크린은 두 개로 만들었다.
메인 함수는 아래와 같이 되어있다.
void main() => runApp(
MaterialApp(
title: 'Navigator',
home: FirstScreen(),
),
);
home을 통하여 시작 스크린을 변경할 수 있다.
- home Screen에서 pop을 하면 화면이 검은색으로 변한다.
첫 번째 스크린 내용이다.
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Go Second Screen'),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondScreen()));
},
),
),
);
}
}
push를 통해서 두 번째 스크린으로 이동을 한다.
두 번째 스크린 내용이다.
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Go First Screen'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
pop을 통해서 다시 첫 번째 스크린으로 이동을 한다.
관련 오류
══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
The following assertion was thrown while handling a gesture:
Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a
descendant of a Navigator widget.
When the exception was thrown, this was the stack:
#0 Navigator.of.<anonymous closure>
package:flutter/…/widgets/navigator.dart:2190
#1 Navigator.of
package:flutter/…/widgets/navigator.dart:2197
#2 Navigator.push
package:flutter/…/widgets/navigator.dart:1801
#3 FirstScreen.build.<anonymous closure>
package:hello_flutter/main.dart:18
#4 _InkResponseState._handleTap
package:flutter/…/material/ink_well.dart:992
#5 _InkResponseState.build.<anonymous closure>
package:flutter/…/material/ink_well.dart:1098
#6 GestureRecognizer.invokeCallback
package:flutter/…/gestures/recognizer.dart:184
#7 TapGestureRecognizer.handleTapUp
package:flutter/…/gestures/tap.dart:524
#8 BaseTapGestureRecognizer._checkUp
package:flutter/…/gestures/tap.dart:284
#9 BaseTapGestureRecognizer.handlePrimaryPointer
package:flutter/…/gestures/tap.dart:219
#10 PrimaryPointerGestureRecognizer.handleEvent
package:flutter/…/gestures/recognizer.dart:477
#11 PointerRouter._dispatch
package:flutter/…/gestures/pointer_router.dart:78
#12 PointerRouter._dispatchEventToRoutes.<anonymous closure>
package:flutter/…/gestures/pointer_router.dart:124
#13 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
#14 PointerRouter._dispatchEventToRoutes
package:flutter/…/gestures/pointer_router.dart:122
#15 PointerRouter.route
package:flutter/…/gestures/pointer_router.dart:108
#16 GestureBinding.handleEvent
package:flutter/…/gestures/binding.dart:220
#17 GestureBinding.dispatchEvent
package:flutter/…/gestures/binding.dart:200
#18 GestureBinding._handlePointerEvent
package:flutter/…/gestures/binding.dart:158
#19 GestureBinding._flushPointerEventQueue
package:flutter/…/gestures/binding.dart:104
#20 GestureBinding._handlePointerDataPacket
package:flutter/…/gestures/binding.dart:88
#24 _invoke1 (dart:ui/hooks.dart:267:10)
#25 _dispatchPointerDataPacket (dart:ui/hooks.dart:176:5)
(elided 3 frames from dart:async)
Handler: "onTap"
Recognizer:
TapGestureRecognizer#24119
════════════════════════════════════════════════════════════════════════════════════════════════════
MaterialApp을 빌드한 클래스에서 navigator를 사용한다면 위의 오류가 뜰 것이다.
MainScreen <------ context
--> MaterialApp
(--> Navigator built within MaterialApp)
--> Scaffold
--> App Bar
--> ...
--> Center
--> FlatButton
stackoverflow.com/questions/50124355/flutter-navigator-not-working/50125296
위의 오류가 뜬다면 main에 MaterialApp을 넣으면 간단히 해결이 된다.
void main() => runApp(
MaterialApp(
title: 'Navigator',
home: FirstScreen(),
),
);
이번에는 Named Route에 대해 알아보자.
MaterialApp에 routes 속성이 있어 각 위젯 별로 이름을 지정하여 그 이름으로 화면을 이동할 수 있는 기능이다.
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
title: 'Navigator',
initialRoute: '/',
routes: {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
'/third': (context) => ThirdScreen(),
},
),
);
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Go Second Screen'),
onPressed: () {
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Go Third Screen'),
onPressed: () {
Navigator.pushNamed(context, '/third');
},
),
),
);
}
}
class ThirdScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ThirdScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Pop!'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
위는 전체적인 코드다.
push, pop을 하며 이동하는 기능은 Navigator와 똑같다.
이번에는 Navigator때와 달리 스크린 3개로 만들었다.
void main() => runApp(
MaterialApp(
title: 'Navigator',
initialRoute: '/',
routes: {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
'/third': (context) => ThirdScreen(),
},
),
);
메인 함수에는 initialRoute와 routes 속성이 추가되었다.
initialRoute속성은 처음 위치를 무엇으로 할지 정하는 속성이다.
Named routed에서는 '/'가 home을 대체하며 home과 '/'를 같이 사용할 수 없다.
- 같이 사용하면 오류가 나타난다.
또한, routes를 통하여 이름을 지정할 수 있기 때문에 Named Routes라고 부른다.
void main() => runApp(
MaterialApp(
title: 'Navigator',
initialRoute: '/second',
routes: {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
'/third': (context) => ThirdScreen(),
},
),
);
initialRoute를 /second로 했을 때의 화면이다. 시작이 second지만 home은 first로 되어있다.
첫 번째 스크린 내용이다.
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Go Second Screen'),
onPressed: () {
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
Navigator와는 달리 pushNamed를 통하여 이동하는 것을 볼 수 있다.
세 번째 스크린 내용이다.
class ThirdScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ThirdScreen'),
),
body: Center(
child: RaisedButton(
child: Text('Pop!'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
pop 할 때는 Navigator와 같이 pop을 사용하여 이전으로 돌아간다.
위의 Navigator와 NamedRoute기능을 통하여 화면 전환을 자유롭게 할 수 있다.
'Language_ > Flutter' 카테고리의 다른 글
[Flutter] Button 총 정리! "Raised, Flat, Icon, FloatingAction" (0) | 2020.10.08 |
---|---|
[Flutter] Bottom Navigation Bar 의 "모든 것" (0) | 2020.09.30 |
[Flutter] AppBar?! AppBar의 "모든 것" (0) | 2020.09.27 |
[Flutter] 외부 Font 추가 및 변경 정리 "Google Font 이용" (0) | 2020.09.27 |
[Flutter] 이미지 추가 & "unable to load asset" 에러 해결 (4) | 2020.09.27 |
댓글