Flutter Navigator 2.0
ソース:https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade
Flutter Navigator 1.0
Navigator-Routeオブジェクトスタック管理部 Route-Navigatorで管理されているオブジェクトペイント画面を使用します.通常はMaterialPageRouteのようなクラスとして実装される. Navigator 1.0は、通常、Navigatorが命名された匿名のルーティングをRouteスタックにプッシュしてポップアップする形式である.
ルーティング定義がない場合は、ウィジェットを呼び出すように画面を移動します.
MaterialAppまたはCupertinAppでルーティングを事前定義し、定義したルーティング名で画面を移動します.Flutter Navigator 2.0
Flutter Navigator 1.0
flut開発者であれば、次のレベルに慣れることができます.
Anonymous routes
ルーティング定義がない場合は、ウィジェットを呼び出すように画面を移動します.
//화면 이동
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return NextPage();
}),
);
//화면 나가기
Navigator.pop(context);
Named routes
MaterialAppまたはCupertinAppでルーティングを事前定義し、定義したルーティング名で画面を移動します.
class App extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
routes: {
//여기서 route name에 따라 이동할 화면을 미리 정의.
'/': (context) => HomeScreen(),
'/details': (context) => DetailScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: FlatButton(
child: Text('View Details'),
onPressed: () {
//화면 이동시 route name을 통해 호출
Navigator.pushNamed(
context,
'/details',
);
},
),
),
);
}
}
Named routions深化プロセス
onGenerateRoute: (settings) {
//route name을 파싱해서 parameter에 따라 동적으로 화면을 호출.
//web의 path처럼 사용 가능.
var uri = Uri.parse(settings.name);
if (uri.pathSegments.length == 2 &&
uri.pathSegments.first == 'details') {
var id = uri.pathSegments[1];
return MaterialPageRoute(builder: (context) => DetailScreen(id: id));
}
return MaterialPageRoute(builder: (context) => UnknownScreen());
},
Flutter Navigator 2.0
Navigator 2.0では、アプリケーションの画面がアプリケーションの状態で動作し、基本プラットフォーム上でルーティングパケットを行う機能を提供するクラスがいくつか追加されています.
Navigator 2.0のインタラクティブグラフィックス
Page
Navigatorヒストリスタックを構成する不変オブジェクト(可変オブジェクト)build(BuildContext context) {
return MaterialApp(
title: 'Books App',
//navigator 안에다 page들을 넣는다.
home: Navigator(
pages: [
//이렇게 MaterialPage를 사용해도 되고
MaterialPage(
child: BooksListScreen(),
),
],
),
);
}
//이런 식으로 Page를 상속 받아서 구현해도 된다.
class BookDetailsPage extends Page {
final Book book;
BookDetailsPage({
this.book,
}) : super(key: ValueKey(book));
Route createRoute(BuildContext context) {
return PageRouteBuilder(
settings: this,
pageBuilder: (context, animation, animation2) {
final tween = Tween(begin: Offset(0.0, 1.0), end: Offset.zero);
final curveTween = CurveTween(curve: Curves.easeInOut);
return SlideTransition(
position: animation.drive(curveTween).drive(tween),
child: BookDetailsScreen(
key: ValueKey(book),
book: book,
),
);
},
);
}
}
Widget
Router
Navigatorが表示するページを設定します.一般的に、ページリストは、基本プラットフォーム(android、ios、web)またはアプリケーションのステータス変更によって引き起こされます. return MaterialApp.router(
title: 'Books App',
routeInformationParser: _routeInformationParser,
routerDelegate: _routerDelegate,
);
RouteInformationParser
RouteInformationProviderからRouteInformationを受信し、ユーザー定義のデータ型に分類します.//RouteInformationParser를 상속 받아서 구현
//BookRoutePath가 user-defined data type
class BookRouteInformationParser extends RouteInformationParser<BookRoutePath> {
//RouteInformation을 파싱해서 user-defined data type으로 리턴
Future<BookRoutePath> parseRouteInformation(
RouteInformation routeInformation) async {
final uri = Uri.parse(routeInformation.location);
// Handle '/book/:id'
if (uri.pathSegments.length == 2) {
if (uri.pathSegments[0] != 'book') return BookRoutePath.unknown();
var remaining = uri.pathSegments[1];
var id = int.tryParse(remaining);
if (id == null) return BookRoutePath.unknown();
return BookRoutePath.details(id);
}
}
//user-defined data type이 각각 어떤 Route와 대응되는지를 정의
RouteInformation restoreRouteInformation(BookRoutePath path) {
if (path.isUnknown) {
return RouteInformation(location: '/404');
}
if (path.isHomePage) {
return RouteInformation(location: '/');
}
if (path.isDetailsPage) {
return RouteInformation(location: '/book/${path.id}');
}
return null;
}
}
RouterDelegate
Routerがappの状態変更をどのように処理して応答を返すかを定義します.class BookRouterDelegate extends RouterDelegate<BookRoutePath>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<BookRoutePath> {
final GlobalKey<NavigatorState> navigatorKey;
//...
BookRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();
BookRoutePath get currentConfiguration {
return _selectedBook == null
? BookRoutePath.home()
: BookRoutePath.details(books.indexOf(_selectedBook));
}
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: [
MaterialPage(
key: ValueKey('BooksListPage'),
child: BooksListScreen(
books: books,
onTapped: _handleBookTapped,
),
),
if (_selectedBook != null)
BookDetailsPage(book: _selectedBook)
],
//Navigator.pop()이 호출 되었을 때 실행되는 부분.
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
// Update the list of pages by setting _selectedBook to null
_selectedBook = null;
show404 = false;
notifyListeners();
return true;
},
);
}
//user-defined data type을 전달받아 적절하게 state를 변경
//예제에서는 _selectedBook을 업데이트
Future<void> setNewRoutePath(BookRoutePath path) async {
if (path.isDetailsPage) {
if (path.id < 0 || path.id > books.length - 1) {
show404 = true;
return;
}
_selectedBook = books[path.id];
} else {
_selectedBook = null;
}
show404 = false;
}
void _handleBookTapped(Book book) {
_selectedBook = book;
notifyListeners();
}
}
BackButtonDispatcher
backbutton actionをRouterに渡します.
の最後の部分
プラットフォーム側で発生した予期せぬスクリーン変更(backbutton(android,web)、URL変更(web)に応答するための機能、より高度なページ制御サポート(multipopまたはpush、スタック内の特定のページの削除など)が追加されました.作業中にマルチpopがサポートされていないか、現在の画面の前の履歴のみが削除されているのは嬉しいニュースです.しかし,概念を全面的に変える更新であるため,移行は容易ではない.
Reference
この問題について(Flutter Navigator 2.0), 我々は、より多くの情報をここで見つけました
https://velog.io/@versatile309/Flutter-Navigator-2.0
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
build(BuildContext context) {
return MaterialApp(
title: 'Books App',
//navigator 안에다 page들을 넣는다.
home: Navigator(
pages: [
//이렇게 MaterialPage를 사용해도 되고
MaterialPage(
child: BooksListScreen(),
),
],
),
);
}
//이런 식으로 Page를 상속 받아서 구현해도 된다.
class BookDetailsPage extends Page {
final Book book;
BookDetailsPage({
this.book,
}) : super(key: ValueKey(book));
Route createRoute(BuildContext context) {
return PageRouteBuilder(
settings: this,
pageBuilder: (context, animation, animation2) {
final tween = Tween(begin: Offset(0.0, 1.0), end: Offset.zero);
final curveTween = CurveTween(curve: Curves.easeInOut);
return SlideTransition(
position: animation.drive(curveTween).drive(tween),
child: BookDetailsScreen(
key: ValueKey(book),
book: book,
),
);
},
);
}
}
Widget return MaterialApp.router(
title: 'Books App',
routeInformationParser: _routeInformationParser,
routerDelegate: _routerDelegate,
);
//RouteInformationParser를 상속 받아서 구현
//BookRoutePath가 user-defined data type
class BookRouteInformationParser extends RouteInformationParser<BookRoutePath> {
//RouteInformation을 파싱해서 user-defined data type으로 리턴
Future<BookRoutePath> parseRouteInformation(
RouteInformation routeInformation) async {
final uri = Uri.parse(routeInformation.location);
// Handle '/book/:id'
if (uri.pathSegments.length == 2) {
if (uri.pathSegments[0] != 'book') return BookRoutePath.unknown();
var remaining = uri.pathSegments[1];
var id = int.tryParse(remaining);
if (id == null) return BookRoutePath.unknown();
return BookRoutePath.details(id);
}
}
//user-defined data type이 각각 어떤 Route와 대응되는지를 정의
RouteInformation restoreRouteInformation(BookRoutePath path) {
if (path.isUnknown) {
return RouteInformation(location: '/404');
}
if (path.isHomePage) {
return RouteInformation(location: '/');
}
if (path.isDetailsPage) {
return RouteInformation(location: '/book/${path.id}');
}
return null;
}
}
class BookRouterDelegate extends RouterDelegate<BookRoutePath>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<BookRoutePath> {
final GlobalKey<NavigatorState> navigatorKey;
//...
BookRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();
BookRoutePath get currentConfiguration {
return _selectedBook == null
? BookRoutePath.home()
: BookRoutePath.details(books.indexOf(_selectedBook));
}
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: [
MaterialPage(
key: ValueKey('BooksListPage'),
child: BooksListScreen(
books: books,
onTapped: _handleBookTapped,
),
),
if (_selectedBook != null)
BookDetailsPage(book: _selectedBook)
],
//Navigator.pop()이 호출 되었을 때 실행되는 부분.
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
// Update the list of pages by setting _selectedBook to null
_selectedBook = null;
show404 = false;
notifyListeners();
return true;
},
);
}
//user-defined data type을 전달받아 적절하게 state를 변경
//예제에서는 _selectedBook을 업데이트
Future<void> setNewRoutePath(BookRoutePath path) async {
if (path.isDetailsPage) {
if (path.id < 0 || path.id > books.length - 1) {
show404 = true;
return;
}
_selectedBook = books[path.id];
} else {
_selectedBook = null;
}
show404 = false;
}
void _handleBookTapped(Book book) {
_selectedBook = book;
notifyListeners();
}
}
プラットフォーム側で発生した予期せぬスクリーン変更(backbutton(android,web)、URL変更(web)に応答するための機能、より高度なページ制御サポート(multipopまたはpush、スタック内の特定のページの削除など)が追加されました.作業中にマルチpopがサポートされていないか、現在の画面の前の履歴のみが削除されているのは嬉しいニュースです.しかし,概念を全面的に変える更新であるため,移行は容易ではない.
Reference
この問題について(Flutter Navigator 2.0), 我々は、より多くの情報をここで見つけました https://velog.io/@versatile309/Flutter-Navigator-2.0テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol