Flutter mulai populer di kalangan pengembang. Sebagian besar pendekatan untuk membangun aplikasi sudah mapan dan digunakan setiap hari dalam pengembangan aplikasi E-commerce. Topik navigasi diturunkan ke latar belakang atau rencana ketiga. API navigasi apa yang disediakan oleh Framework? Pendekatan apa yang telah dikembangkan? Bagaimana pendekatan ini digunakan dan apa gunanya?
pengantar
Mari kita mulai dengan apa itu navigasi? Navigasi adalah metode yang memungkinkan Anda untuk menavigasi antara antarmuka pengguna dengan parameter tertentu.
Misalnya, di dunia IOS, UIViewController mengatur navigasi, dan di Android - komponen Navigasi. Apa yang Flutter sediakan?
Navigator
Layar di Flutter disebut rute. Untuk menavigasi di antara rute, ada kelas Navigator yang memiliki API ekstensif untuk mengimplementasikan berbagai jenis navigasi.
Menavigasi ke dan kembali dari rute baru
Mari kita mulai dengan sederhana. Navigasi ke layar baru (rute) dipanggil dengan metode push (), yang mengambil satu argumen - ini adalah Rute.
Navigator.push(MaterialPageRoute(builder: (BuildContext context) => MyPage()));
Mari kita lihat lebih dekat pada panggilan metode push:
Navigator — , .
Navigator.push() — route .
MaterialPageRoute() — route, .
builder — MaterialPageRoute, .
MyPage — Stateful/Stateless Widget
route
pop().
Navigator.pop();
builder . Navigator, build.
Navigator.push(context, MaterialPageRoute(builder: (context) => MyPage(someData: data)));
MyPage ( ).
pop() .
Navigator.pop(data);
Navigator State
Navigator, MaterialApp/CupertinoApp/WidgetsApp. State API .
Stack. "call flow" NavigatorState.
vs
. route, .
:
, — ?
: , . .
, — ?
: , .
Imperative vs Declarative Programming
. . Route. Flutter route, MaterialPageRoute CupertinoPageRoute. CupertinoPageRoute title, settings.
:
Navigator.push(
context,
CupertinoPageRoute<T>(
title: "Setting",
builder: (BuildContext context) => MyPage(),
settings: RouteSettings(name:"my_page"),
),
);
route ViewModel/Controller/BLoC/… .
MyPage CupertinoPageRoute. push .
:
, route .
. .
:
Navigator.pushNamed(context, '/my_page');
. " " .
MaterialApp/CupertinoApp/WidgetsApp. 2 onGenerateRoute onUnknownRoute .
:
MaterialApp(
onUnknownRoute: (settings) => CupertinoPageRoute(
builder: (context) {
return UndefinedView(name: settings.name);
}
),
onGenerateRoute: (settings) {
if (settings.name == '\my_page') {
return CupertinoPageRoute(
title: "MyPage",
settings: settings,
builder: (context) => MyPage(),
);
}
//
},
);
:
onGenerateRoute — Navigator.pushNamed(). route.
onUnknownRoute — onGenerateRoute null. route, web — 404 page.
. , .
. .
:
- showAboutDialog
- showBottomSheet
- showDatePicker
- showGeneralDialog
- showMenu
- showModalBottomSheet
- showSearch
- showTimePicker
- showCupertinoDialog
- showDialog
- showLicensePage
- showCupertinoModalPopup
. API, .
?
, showGeneralDialog.
:
Future<T> showGeneralDialog<T>({
@required BuildContext context,
@required RoutePageBuilder pageBuilder,
bool barrierDismissible,
String barrierLabel,
Color barrierColor,
Duration transitionDuration,
RouteTransitionsBuilder transitionBuilder,
bool useRootNavigator = true,
RouteSettings routeSettings,
}) {
assert(pageBuilder != null);
assert(useRootNavigator != null);
assert(!barrierDismissible || barrierLabel != null);
return Navigator.of(context, rootNavigator: useRootNavigator).push<T>(_DialogRoute<T>(
pageBuilder: pageBuilder,
barrierDismissible: barrierDismissible,
barrierLabel: barrierLabel,
barrierColor: barrierColor,
transitionDuration: transitionDuration,
transitionBuilder: transitionBuilder,
settings: routeSettings,
));
}
. showGeneralDialog push NavigatorState _DialogRoute(). , .
— route .
route
"every thins is a route", . , route .
route Flutter — PageRoute PopupRoute.
PageRoute — route, .
PopupRoute — route, route.
PageRoute:
- MaterialPageRoute
- CupertinoPageRoute
- _SearchPageRoute
- PageRouteBuilder
PopupRoute:
- _ContexMenuRoute
- _DialogRoute
- _ModalBottomSheetRoute
- _CupertinoModalPopupRoute
- _PopupMenuRoute
PopupRoute , .
:
, .
Best practices
, " ?". , API , . .
:
- .
- BuildContext ( , BuildContext).
- . route, CupertinoPageRoute, BottomSheetRoute, DialogRoute ..
:
abstract class IRouter {
Future<T> routeTo<T extends Object>(RouteBundle bundle);
Future<bool> back<T extends Object>({T data, bool rootNavigator});
GlobalKey<NavigatorState> rootNavigatorKey;
}
:
routeTo - .
back — .
rootNavigatorKey — GlobalKey NavigatorState.
, .
class Router implements IRouter {
@override
GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>();
@override
Future<T> routeTo<T>(RouteBundle bundle) async {
// Push logic here
}
@override
Future<bool> back<T>({T data, bool rootNavigator = false}) async {
// Back logic here
}
}
, routeTo().
@override
Future<T> routeTo<T>(RouteBundle bundle) async {
assert(bundle != null, "The bundle [RouteBundle.bundle] is null");
NavigatorState rootState = rootNavigatorKey.currentState;
assert(rootState != null, 'rootState [NavigatorState] is null');
switch (bundle.route) {
case "/routeExample":
return await rootState.push(
_buildRoute<T>(
bundle: bundle,
child: RouteExample(),
),
);
case "/my_page":
return await rootState.push(
_buildRoute<T>(
bundle: bundle,
child: MyPage(),
),
);
default:
throw Exception('Route is not found');
}
}
root NavigatorState ( WidgetsApp) push RouteBundle .
RouteBundle. , .
enum ContainerType {
/// The parent type is [Scaffold].
///
/// In IOS route with an iOS transition [CupertinoPageRoute].
/// In Android route with an Android transition [MaterialPageRoute].
///
scaffold,
/// Used for show child in dialog.
///
/// Route with [DialogRoute].
dialog,
/// Used for show child in [BottomSheet].
///
/// Route with [ModalBottomSheetRoute].
bottomSheet,
/// Used for show child only.
/// [AppBar] and other features is not implemented.
window,
}
class RouteBundle {
/// Creates a bundle that can be used for [Router].
RouteBundle({
this.route,
this.containerType,
});
/// The route for current navigation.
///
/// See [Routes] for details.
final String route;
/// The current status of this animation.
final ContainerType containerType;
}
enum ContainerType — , .
RouteBundle — - route.
_buildRoute. , route .
Route<T> _buildRoute<T>({@required RouteBundle bundle, @required Widget child}) {
assert(bundle.containerType != null, "The bundle.containerType [RouteBundle.containerType] is null");
switch (bundle.containerType) {
case ContainerType.scaffold:
return CupertinoPageRoute<T>(
title: bundle.title,
builder: (BuildContext context) => child,
settings: RouteSettings(name: bundle.route),
);
case ContainerType.dialog:
return DialogRoute<T>(
title: '123',
settings: RouteSettings(name: bundle.route),
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return child;
},
);
case ContainerType.bottomSheet:
return ModalBottomSheetRoute<T>(
settings: RouteSettings(name: bundle.route),
isScrollControlled: true,
builder: (BuildContext context) => child,
);
case ContainerType.window:
return CupertinoPageRoute<T>(
settings: RouteSettings(name: bundle.route),
builder: (BuildContext context) => child,
);
default:
throw Exception('ContainerType is not found');
}
}
ModalBottomSheetRoute DialogRoute, . route Material Flutter.
back.
@override
Future<bool> back<T>({T data, bool rootNavigator = false}) async {
NavigatorState rootState = rootNavigatorKey.currentState;
return await (rootState).maybePop<T>(data);
}
rootNavigatorKey App :
MaterialApp(
navigatorKey: widget.router.rootNavigatorKey,
home: Home()
);
, route. - "" , , Dependency Injection.
router.routeTo(RouteBundle(route: '/my_page', containerType: ContainerType.window));
, :
- BuildContext GlobalKey
- route View
Flutter , .