Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Flutter Navigation by Bartosz Remisz

Flutter Navigation by Bartosz Remisz

Projekt nawigatora
Przekazywanie parametrów (2 sposoby)
Przykład z ekranem logowania
Animacje przejść
Zagnieżdżenie nawigacji
Utrzymywanie danych i nawigatora pomiędzy uruchomieniami
Tips & tricks

Rafał Dziuryk

March 02, 2020
Tweet

More Decks by Rafał Dziuryk

Other Decks in Programming

Transcript

  1. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks
  2. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks
  3. Wymagania • Dodanie nowego ekranu. • Cofnięcie się. • Powrót

    do ekranu głównego. • Dostęp z dowolnego miejsca w kodzie. • Oparty o BLoC-a. 1 enum NavigationType { 2 PUSH, 3 POP, 4 HOME 5 } 1 enum NavigationType { 5 } BlocProvider.of<NavigationBloc>(context).add(...);
  4. Wymagania • Dodanie nowego ekranu. • Cofnięcie się. • Powrót

    do ekranu głównego. • Dostęp z dowolnego miejsca w kodzie. • Oparty o BLoC-a. 1 enum NavigationType { 2 PUSH, 3 POP, 4 HOME 5 } 1 enum NavigationType { 2 PUSH, 5 } BlocProvider.of<NavigationBloc>(context).add(...);
  5. Wymagania • Dodanie nowego ekranu. • Cofnięcie się. • Powrót

    do ekranu głównego. • Dostęp z dowolnego miejsca w kodzie. • Oparty o BLoC-a. 1 enum NavigationType { 2 PUSH, 3 POP, 4 HOME 5 } 1 enum NavigationType { 2 PUSH, 3 POP, 5 } BlocProvider.of<NavigationBloc>(context).add(...);
  6. Wymagania • Dodanie nowego ekranu. • Cofnięcie się. • Powrót

    do ekranu głównego. • Dostęp z dowolnego miejsca w kodzie. • Oparty o BLoC-a. 1 enum NavigationType { 2 PUSH, 3 POP, 4 HOME 5 } BlocProvider.of<NavigationBloc>(context).add(...);
  7. Wymagania • Dodanie nowego ekranu. • Cofnięcie się. • Powrót

    do ekranu głównego. • Dostęp z dowolnego miejsca w kodzie. • Oparty o BLoC-a. 1 enum NavigationType { 2 PUSH, 3 POP, 4 HOME 5 } BlocProvider.of<NavigationBloc>(context).add(...);
  8. Wymagania • Dodanie nowego ekranu. • Cofnięcie się. • Powrót

    do ekranu głównego. • Dostęp z dowolnego miejsca w kodzie. • Oparty o BLoC-a. 1 enum NavigationType { 2 PUSH, 3 POP, 4 HOME 5 } BlocProvider.of<NavigationBloc>(context).add(...);
  9. Oparty o BLoC-a. 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> {

    2 final GlobalKey<NavigatorState> navigatorKey; 3 4 NavigationBloc({this.navigatorKey});
  10. Oparty o BLoC-a. 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> {

    2 final GlobalKey<NavigatorState> navigatorKey; 3 4 NavigationBloc({this.navigatorKey}); Aplikacja
  11. Oparty o BLoC-a. 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> {

    2 final GlobalKey<NavigatorState> navigatorKey; 3 4 NavigationBloc({this.navigatorKey}); Zdarzenia Aplikacja
  12. Oparty o BLoC-a. 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> {

    2 final GlobalKey<NavigatorState> navigatorKey; 3 4 NavigationBloc({this.navigatorKey}); Zdarzenia Aplikacja
  13. Oparty o BLoC-a. 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> {

    2 final GlobalKey<NavigatorState> navigatorKey; 3 4 NavigationBloc({this.navigatorKey}); Zdarzenia Obserwator Aplikacja Stany
  14. Oparty o BLoC-a. 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> {

    2 final GlobalKey<NavigatorState> navigatorKey; 3 4 NavigationBloc({this.navigatorKey}); Zdarzenia Obserwator Aplikacja Stany mapEventToState
  15. Ekrany 1 class AppPage1 extends StatelessWidget { 2 3 @override

    4 Widget build(BuildContext context) { 5 return Scaffold( 6 appBar: AppBar(title: Text("App Page 1"),), 7 body: SafeArea( 8 child: Center( 9 child: Column( 10 children: <Widget>[ 11 RaisedButton( 12 onPressed: () {
 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionPushNamed("/page2")); 15 child: Text("Go Page 2"), 16 ),],),),),);} 17 } 
 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionPushNamed("/page2"));},
  16. Ekrany 1 class AppPage2 extends StatelessWidget { 2 3 @override

    4 Widget build(BuildContext context) { 5 return Scaffold( 6 appBar: AppBar(title: Text("App Page 2"),), 7 body: SafeArea( 8 child: Center( 9 child: Column( 10 children: <Widget>[ 11 RaisedButton( 12 onPressed: () {
 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionPushNamed("/page3"));}, 15 child: Text("Go Page 3"), 16 ),],),),),);} 17 } 
 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionPushNamed("/page3"));},
  17. Ekrany 1 class AppPage3 extends StatelessWidget { 2 3 @override

    4 Widget build(BuildContext context) { 5 return Scaffold( 6 appBar: AppBar(title: Text("App Page 3"),), 7 body: SafeArea( 8 child: Center( 9 child: Column( 10 children: <Widget>[ 11 RaisedButton( 12 onPressed: () { 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionHome());},}, 15 child: Text("go Home"), 16 ),],),),),);} 17 } 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionHome());},},
  18. Klasy nawigacji 1 class NavigatorActionPop extends NavigatorAction { 2 NavigatorActionPop()

    : super(navigationType: NavigationType.POP); 3 } 4 5 class NavigatorActionHome extends NavigatorAction { 6 NavigatorActionHome(): super(navigationType: NavigationType.HOME); 7 } 8 9 class NavigatorActionPushNamed extends NavigatorAction { 10 final String path; 11 12 NavigatorActionPushNamed(this.path) 13 : super(navigationType: NavigationType.PUSH); 14 } 6 abstract class NavigatorAction { 7 final NavigationType navigationType; 8 9 NavigatorAction({this.navigationType}); 10 }
  19. Klasy nawigacji 1 class NavigatorActionPop extends NavigatorAction { 2 NavigatorActionPop()

    : super(navigationType: NavigationType.POP); 3 } 4 5 class NavigatorActionHome extends NavigatorAction { 6 NavigatorActionHome(): super(navigationType: NavigationType.HOME); 7 } 8 9 class NavigatorActionPushNamed extends NavigatorAction { 10 final String path; 11 12 NavigatorActionPushNamed(this.path) 13 : super(navigationType: NavigationType.PUSH); 14 } 6 abstract class NavigatorAction { 7 final NavigationType navigationType; 8 9 NavigatorAction({this.navigationType}); 10 } 1 class NavigatorActionPop extends NavigatorAction { 2 NavigatorActionPop() : super(navigationType: NavigationType.POP); 3 }
  20. Klasy nawigacji 1 class NavigatorActionPop extends NavigatorAction { 2 NavigatorActionPop()

    : super(navigationType: NavigationType.POP); 3 } 4 5 class NavigatorActionHome extends NavigatorAction { 6 NavigatorActionHome(): super(navigationType: NavigationType.HOME); 7 } 8 9 class NavigatorActionPushNamed extends NavigatorAction { 10 final String path; 11 12 NavigatorActionPushNamed(this.path) 13 : super(navigationType: NavigationType.PUSH); 14 } 6 abstract class NavigatorAction { 7 final NavigationType navigationType; 8 9 NavigatorAction({this.navigationType}); 10 } 5 class NavigatorActionHome extends NavigatorAction { 6 NavigatorActionHome(): super(navigationType: NavigationType.HOME); 7 }
  21. Klasy nawigacji 1 class NavigatorActionPop extends NavigatorAction { 2 NavigatorActionPop()

    : super(navigationType: NavigationType.POP); 3 } 4 5 class NavigatorActionHome extends NavigatorAction { 6 NavigatorActionHome(): super(navigationType: NavigationType.HOME); 7 } 8 9 class NavigatorActionPushNamed extends NavigatorAction { 10 final String path; 11 12 NavigatorActionPushNamed(this.path) 13 : super(navigationType: NavigationType.PUSH); 14 } 6 abstract class NavigatorAction { 7 final NavigationType navigationType; 8 9 NavigatorAction({this.navigationType}); 10 } 9 class NavigatorActionPushNamed extends NavigatorAction { 10 final String path; 11 12 NavigatorActionPushNamed(this.path) 13 : super(navigationType: NavigationType.PUSH); 14 }
  22. Nawigator 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> { 2 3

    @override 4 Stream<dynamic> mapEventToState(NavigatorAction event) async* { 5 switch (event.navigationType) { 6 case NavigationType.POP: 7 yield navigatorKey.currentState.pop(); 8 break; 9 case NavigationType.HOME: 10 navigatorKey.currentState.popUntil((route) => route.isFirst); 11 yield true; 12 break; 13 case NavigationType.PUSH: 14 final pushAction = event as NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path); 16 break; 17 default: 18 yield null; 19 break; 20 } 21 }
  23. Nawigator 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> { 2 3

    @override 4 Stream<dynamic> mapEventToState(NavigatorAction event) async* { 5 switch (event.navigationType) { 6 case NavigationType.POP: 7 yield navigatorKey.currentState.pop(); 8 break; 9 case NavigationType.HOME: 10 navigatorKey.currentState.popUntil((route) => route.isFirst); 11 yield true; 12 break; 13 case NavigationType.PUSH: 14 final pushAction = event as NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path); 16 break; 17 default: 18 yield null; 19 break; 20 } 21 } 3 @override 4 Stream<dynamic> mapEventToState(NavigatorAction event) async* { 5 switch (event.navigationType) { 17 default: 18 yield null; 19 break; 20 } 21 }
  24. Nawigator 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> { 2 3

    @override 4 Stream<dynamic> mapEventToState(NavigatorAction event) async* { 5 switch (event.navigationType) { 6 case NavigationType.POP: 7 yield navigatorKey.currentState.pop(); 8 break; 9 case NavigationType.HOME: 10 navigatorKey.currentState.popUntil((route) => route.isFirst); 11 yield true; 12 break; 13 case NavigationType.PUSH: 14 final pushAction = event as NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path); 16 break; 17 default: 18 yield null; 19 break; 20 } 21 } 6 case NavigationType.POP: 7 yield navigatorKey.currentState.pop(); 8 break;
  25. Nawigator 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> { 2 3

    @override 4 Stream<dynamic> mapEventToState(NavigatorAction event) async* { 5 switch (event.navigationType) { 6 case NavigationType.POP: 7 yield navigatorKey.currentState.pop(); 8 break; 9 case NavigationType.HOME: 10 navigatorKey.currentState.popUntil((route) => route.isFirst); 11 yield true; 12 break; 13 case NavigationType.PUSH: 14 final pushAction = event as NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path); 16 break; 17 default: 18 yield null; 19 break; 20 } 21 } 9 case NavigationType.HOME: 10 navigatorKey.currentState.popUntil((route) => route.isFirst); 11 yield true; 12 break;
  26. Nawigator 1 class NavigationBloc extends Bloc<NavigatorAction, dynamic> { 2 3

    @override 4 Stream<dynamic> mapEventToState(NavigatorAction event) async* { 5 switch (event.navigationType) { 6 case NavigationType.POP: 7 yield navigatorKey.currentState.pop(); 8 break; 9 case NavigationType.HOME: 10 navigatorKey.currentState.popUntil((route) => route.isFirst); 11 yield true; 12 break; 13 case NavigationType.PUSH: 14 final pushAction = event as NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path); 16 break; 17 default: 18 yield null; 19 break; 20 } 21 } 13 case NavigationType.PUSH: 14 final pushAction = event as NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path); 16 break;
  27. Obsługa ścieżek 1 typedef Widget RouteHandler(BuildContext context); 2 3 class

    Router { 4 static final appRouter = Router(); 5 6 final HashMap<String, RouteHandler> _routeTree = HashMap(); 7 8 void define(String path, RouteHandler handler) { 9 _routeTree.putIfAbsent(path, () => handler); 10 } 11 12 RouteHandler match(String path) 13 { 14 return _routeTree[path]; 15 } 16 17 18 Route<dynamic> generator(RouteSettings routeSettings) 19 { 20 //what if no match? 404 page, do nothing, go back, error. 21 return MaterialPageRoute(builder: match(routeSettings.name)); 22 } 23 }
  28. Obsługa ścieżek 1 typedef Widget RouteHandler(BuildContext context); 2 3 class

    Router { 4 static final appRouter = Router(); 5 6 final HashMap<String, RouteHandler> _routeTree = HashMap(); 7 8 void define(String path, RouteHandler handler) { 9 _routeTree.putIfAbsent(path, () => handler); 10 } 11 12 RouteHandler match(String path) 13 { 14 return _routeTree[path]; 15 } 16 17 18 Route<dynamic> generator(RouteSettings routeSettings) 19 { 20 //what if no match? 404 page, do nothing, go back, error. 21 return MaterialPageRoute(builder: match(routeSettings.name)); 22 } 23 } 1 typedef Widget RouteHandler(BuildContext context);
  29. Obsługa ścieżek 1 typedef Widget RouteHandler(BuildContext context); 2 3 class

    Router { 4 static final appRouter = Router(); 5 6 final HashMap<String, RouteHandler> _routeTree = HashMap(); 7 8 void define(String path, RouteHandler handler) { 9 _routeTree.putIfAbsent(path, () => handler); 10 } 11 12 RouteHandler match(String path) 13 { 14 return _routeTree[path]; 15 } 16 17 18 Route<dynamic> generator(RouteSettings routeSettings) 19 { 20 //what if no match? 404 page, do nothing, go back, error. 21 return MaterialPageRoute(builder: match(routeSettings.name)); 22 } 23 } 3 class Router { 4 static final appRouter = Router(); 5 6 final HashMap<String, RouteHandler> _routeTree = HashMap(); 7
  30. Obsługa ścieżek 1 typedef Widget RouteHandler(BuildContext context); 2 3 class

    Router { 4 static final appRouter = Router(); 5 6 final HashMap<String, RouteHandler> _routeTree = HashMap(); 7 8 void define(String path, RouteHandler handler) { 9 _routeTree.putIfAbsent(path, () => handler); 10 } 11 12 RouteHandler match(String path) 13 { 14 return _routeTree[path]; 15 } 16 17 18 Route<dynamic> generator(RouteSettings routeSettings) 19 { 20 //what if no match? 404 page, do nothing, go back, error. 21 return MaterialPageRoute(builder: match(routeSettings.name)); 22 } 23 } 8 void define(String path, RouteHandler handler) { 9 _routeTree.putIfAbsent(path, () => handler); 10 } 12 RouteHandler match(String path) 13 { 14 return _routeTree[path]; 15 }
  31. Obsługa ścieżek 1 typedef Widget RouteHandler(BuildContext context); 2 3 class

    Router { 4 static final appRouter = Router(); 5 6 final HashMap<String, RouteHandler> _routeTree = HashMap(); 7 8 void define(String path, RouteHandler handler) { 9 _routeTree.putIfAbsent(path, () => handler); 10 } 11 12 RouteHandler match(String path) 13 { 14 return _routeTree[path]; 15 } 16 17 18 Route<dynamic> generator(RouteSettings routeSettings) 19 { 20 //what if no match? 404 page, do nothing, go back, error. 21 return MaterialPageRoute(builder: match(routeSettings.name)); 22 } 23 } 18 Route<dynamic> generator(RouteSettings routeSettings) 19 { 20 //what if no match? 404 page, do nothing, go back, error. 21 return MaterialPageRoute(builder: match(routeSettings.name)); 22 } 23 }
  32. Implementacja ścieżek 1 class AppPage1 extends StatelessWidget { 2 static

    RouteHandler pageHandler = (BuildContext context) { 3 return AppPage1(); 4 }; 1 class AppPage2 extends StatelessWidget { 2 static RouteHandler pageHandler = (BuildContext context) { 3 return AppPage2(); 4 }; 1 class AppPage3 extends StatelessWidget { 2 static RouteHandler pageHandler = (BuildContext context) { 3 return AppPage3(); 4 };
  33. Implementacja ścieżek 1 class AppPage1 extends StatelessWidget { 2 static

    RouteHandler pageHandler = (BuildContext context) { 3 return AppPage1(); 4 }; 1 class AppPage2 extends StatelessWidget { 2 static RouteHandler pageHandler = (BuildContext context) { 3 return AppPage2(); 4 }; 1 class AppPage3 extends StatelessWidget { 2 static RouteHandler pageHandler = (BuildContext context) { 3 return AppPage3(); 4 };
  34. Konfiguracja ścieżek 1 class RouteList { 2 3 static String

    home = "/"; //known as page1 4 static String page1 = "/page2"; 5 static String page2 = "/page3"; 6 7 static void configureRoutes(Router router) { 8 router.define(home, AppPage1.pageHandler); 9 router.define(page1, AppPage2.pageHandler); 10 router.define(page2, AppPage3.pageHandler); 11 } 12 13 }
  35. Konfiguracja ścieżek 1 class RouteList { 2 3 static String

    home = "/"; //known as page1 4 static String page1 = "/page2"; 5 static String page2 = "/page3"; 6 7 static void configureRoutes(Router router) { 8 router.define(home, AppPage1.pageHandler); 9 router.define(page1, AppPage2.pageHandler); 10 router.define(page2, AppPage3.pageHandler); 11 } 12 13 } 1 class RouteList { 2 3 static String home = "/"; //known as page1 4 static String page1 = "/page2"; 5 static String page2 = "/page3";
  36. Konfiguracja ścieżek 1 class RouteList { 2 3 static String

    home = "/"; //known as page1 4 static String page1 = "/page2"; 5 static String page2 = "/page3"; 6 7 static void configureRoutes(Router router) { 8 router.define(home, AppPage1.pageHandler); 9 router.define(page1, AppPage2.pageHandler); 10 router.define(page2, AppPage3.pageHandler); 11 } 12 13 } 7 static void configureRoutes(Router router) { 8 router.define(home, AppPage1.pageHandler); 9 router.define(page1, AppPage2.pageHandler); 10 router.define(page2, AppPage3.pageHandler);
  37. Konfiguracja ścieżek 1 class RouteList { 2 3 static String

    home = "/"; //known as page1 4 static String page1 = "/page2"; 5 static String page2 = "/page3"; 6 7 static void configureRoutes(Router router) { 8 router.define(home, AppPage1.pageHandler); 9 router.define(page1, AppPage2.pageHandler); 10 router.define(page2, AppPage3.pageHandler); 11 } 12 13 }
  38. Material App 1 class MyApp extends StatelessWidget { 2 final

    GlobalKey<NavigatorState> _navigatorKey = GlobalKey(); 3 4 MyApp() { 5 RouteList.configureRoutes(Router.appRouter); 6 } 7 8 @override 9 Widget build(BuildContext context) { 10 return BlocProvider<NavigationBloc>( 11 create: (_) => NavigationBloc(navigatorKey: _navigatorKey), 12 child: MaterialApp( 13 navigatorKey: _navigatorKey, 14 home: AppPage1(), 15 title: 'Flutter Navigation Demo', 16 theme: getTheme(), 17 onGenerateRoute: Router.appRouter.generator, 18 )); 19 } 20 }
  39. Material App 1 class MyApp extends StatelessWidget { 2 final

    GlobalKey<NavigatorState> _navigatorKey = GlobalKey(); 3 4 MyApp() { 5 RouteList.configureRoutes(Router.appRouter); 6 } 7 8 @override 9 Widget build(BuildContext context) { 10 return BlocProvider<NavigationBloc>( 11 create: (_) => NavigationBloc(navigatorKey: _navigatorKey), 12 child: MaterialApp( 13 navigatorKey: _navigatorKey, 14 home: AppPage1(), 15 title: 'Flutter Navigation Demo', 16 theme: getTheme(), 17 onGenerateRoute: Router.appRouter.generator, 18 )); 19 } 20 } 2 final GlobalKey<NavigatorState> _navigatorKey = GlobalKey(); 7 8 @override 9 Widget build(BuildContext context) { 10 return BlocProvider<NavigationBloc>( 11 create: (_) => NavigationBloc(navigatorKey: _navigatorKey), 12 child: MaterialApp( 13 navigatorKey: _navigatorKey,
  40. Material App 1 class MyApp extends StatelessWidget { 2 final

    GlobalKey<NavigatorState> _navigatorKey = GlobalKey(); 3 4 MyApp() { 5 RouteList.configureRoutes(Router.appRouter); 6 } 7 8 @override 9 Widget build(BuildContext context) { 10 return BlocProvider<NavigationBloc>( 11 create: (_) => NavigationBloc(navigatorKey: _navigatorKey), 12 child: MaterialApp( 13 navigatorKey: _navigatorKey, 14 home: AppPage1(), 15 title: 'Flutter Navigation Demo', 16 theme: getTheme(), 17 onGenerateRoute: Router.appRouter.generator, 18 )); 19 } 20 } 4 MyApp() { 5 RouteList.configureRoutes(Router.appRouter); 6 } 
 
 
 
 
 
 
 
 
 
 17 onGenerateRoute: Router.appRouter.generator,
  41. Material App 1 class MyApp extends StatelessWidget { 2 final

    GlobalKey<NavigatorState> _navigatorKey = GlobalKey(); 3 4 MyApp() { 5 RouteList.configureRoutes(Router.appRouter); 6 } 7 8 @override 9 Widget build(BuildContext context) { 10 return BlocProvider<NavigationBloc>( 11 create: (_) => NavigationBloc(navigatorKey: _navigatorKey), 12 child: MaterialApp( 13 navigatorKey: _navigatorKey, 14 home: AppPage1(), 15 title: 'Flutter Navigation Demo', 16 theme: getTheme(), 17 onGenerateRoute: Router.appRouter.generator, 18 )); 19 } 20 }
  42. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks
  43. Obsługa ścieżek 1 typedef Widget RouteHandler(BuildContext context, 2 {Map<String, dynamic>

    params}); 1 typedef Widget RouteHandler(BuildContext context);
  44. Obsługa ścieżek - Opcja 1 1 Route<dynamic> generator(RouteSettings routeSettings) {

    2 //what if no match? 404 page, do nothing, go back, error. 3 4 Map<String, dynamic> params; 5 6 if (routeSettings.arguments != null && 7 routeSettings.arguments is Map<String, dynamic>) { 8 params = routeSettings.arguments as Map<String, dynamic>; 9 } 10 11 return MaterialPageRoute( 12 builder: (BuildContext context) => 13 match(routeSettings.name)(context, params: params)); 14 } 15 } 1 Route<dynamic> generator(RouteSettings routeSettings) { 
 
 
 
 
 
 
 
 
 
 
 
 

  45. Obsługa ścieżek - Opcja 1 1 Route<dynamic> generator(RouteSettings routeSettings) {

    2 //what if no match? 404 page, do nothing, go back, error. 3 4 Map<String, dynamic> params; 5 6 if (routeSettings.arguments != null && 7 routeSettings.arguments is Map<String, dynamic>) { 8 params = routeSettings.arguments as Map<String, dynamic>; 9 } 10 11 return MaterialPageRoute( 12 builder: (BuildContext context) => 13 match(routeSettings.name)(context, params: params)); 14 } 15 } 4 Map<String, dynamic> params; 5 6 if (routeSettings.arguments != null && 7 routeSettings.arguments is Map<String, dynamic>) { 8 params = routeSettings.arguments as Map<String, dynamic>; 9 } 10 11 return MaterialPageRoute( 12 builder: (BuildContext context) => 13 match(routeSettings.name)(context, params: params));
  46. Klasa pomocnicza 1 class NavigatorActionPushNamed extends NavigatorAction { 2 final

    String path; 3 final Map<String, dynamic> params; 4 5 NavigatorActionPushNamed(this.path, {this.params}) 6 : super(navigationType: NavigationType.PUSH); 7 } 1 class NavigatorActionPushNamed extends NavigatorAction { 1 class NavigatorActionPush extends NavigatorAction { 2 final RouteHandler handler; 3 4 NavigatorActionPush(this.handler) 5 : super(navigationType: NavigationType.PUSH); 6 } 1 class NavigatorActionPush extends NavigatorAction {
  47. Klasa pomocnicza 1 class NavigatorActionPushNamed extends NavigatorAction { 2 final

    String path; 3 final Map<String, dynamic> params; 4 5 NavigatorActionPushNamed(this.path, {this.params}) 6 : super(navigationType: NavigationType.PUSH); 7 } 1 class NavigatorActionPush extends NavigatorAction { 2 final RouteHandler handler; 3 4 NavigatorActionPush(this.handler) 5 : super(navigationType: NavigationType.PUSH); 6 } 1 class NavigatorActionPushNamed extends NavigatorAction { 3 final Map<String, dynamic> params; 4 5 NavigatorActionPushNamed(this.path, {this.params}) 

  48. Klasa pomocnicza 1 class NavigatorActionPushNamed extends NavigatorAction { 2 final

    String path; 3 final Map<String, dynamic> params; 4 5 NavigatorActionPushNamed(this.path, {this.params}) 6 : super(navigationType: NavigationType.PUSH); 7 } 1 class NavigatorActionPush extends NavigatorAction { 2 final RouteHandler handler; 3 4 NavigatorActionPush(this.handler) 5 : super(navigationType: NavigationType.PUSH); 6 } 1 class NavigatorActionPushNamed extends NavigatorAction { 3 final Map<String, dynamic> params; 4 5 NavigatorActionPushNamed(this.path, {this.params}) 
 1 class NavigatorActionPush extends NavigatorAction { 2 final RouteHandler handler; 3 4 NavigatorActionPush(this.handler) 5 : super(navigationType: NavigationType.PUSH); 6 }
  49. Nawigator 13 case NavigationType.PUSH: 14 final pushAction = event as

    NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path, arguments: pushAction.params); 
 
 arguments: pushAction.params); 1 case NavigationType.PUSH: 2 final pushAction = event as NavigatorActionPush; 3 yield navigatorKey.currentState 4 .push(MaterialPageRoute(builder: pushAction.handler));
  50. Nawigator 13 case NavigationType.PUSH: 14 final pushAction = event as

    NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path, arguments: pushAction.params); 1 case NavigationType.PUSH: 2 final pushAction = event as NavigatorActionPush; 3 yield navigatorKey.currentState 4 .push(MaterialPageRoute(builder: pushAction.handler));
  51. Nawigator 13 case NavigationType.PUSH: 14 final pushAction = event as

    NavigatorActionPushNamed; 15 yield navigatorKey.currentState.pushNamed(pushAction.path, arguments: pushAction.params); 1 case NavigationType.PUSH: 2 final pushAction = event as NavigatorActionPush; 3 yield navigatorKey.currentState 4 .push(MaterialPageRoute(builder: pushAction.handler)); 
 4 .push(MaterialPageRoute(builder: pushAction.handler)); 
 15 pushNamed(pushAction.path, arguments: pushAction.params);
  52. Implementacja ścieżek 1 class AppPage3 extends StatelessWidget { 2 final

    int pageNumber; 3 4 AppPage3({this.pageNumber}); [...] 11 RaisedButton( 12 onPressed: () { 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionHome()); 15 }, 16 child: Text("go Home from $pageNumber"), [...] 1 class AppPage3 extends StatelessWidget { 2 final int pageNumber; 3 4 AppPage3({this.pageNumber}); [...] 16 child: Text("go Home from $pageNumber"), [...]
  53. Implementacja ścieżek - Opcja 1 1 class AppPage3 extends StatelessWidget

    { 2 static const KEY_PARAM_1 = "NazwaPolaTekstowego"; 3 4 static RouteHandler pageHandler = 5 (BuildContext context, {Map<String, dynamic> params}) { 6 var pageNumberToDisplay = 3; 7 if (params != null) { 8 if (params.containsKey(KEY_PARAM_1) && params[KEY_PARAM_1] is int) { 9 pageNumberToDisplay = params[KEY_PARAM_1] as int; 10 } 11 } 12 return AppPage3(pageNumber: pageNumberToDisplay); 13 }; 14 15 final int pageNumber; 16 17 AppPage3({this.pageNumber}); 2 static const KEY_PARAM_1 = "NazwaPolaTekstowego"; 3 4 static RouteHandler pageHandler = 5 (BuildContext context, {Map<String, dynamic> params}) { 
 
 
 
 
 
 
 

  54. Implementacja ścieżek - Opcja 1 1 class AppPage3 extends StatelessWidget

    { 2 static const KEY_PARAM_1 = "NazwaPolaTekstowego"; 3 4 static RouteHandler pageHandler = 5 (BuildContext context, {Map<String, dynamic> params}) { 6 var pageNumberToDisplay = 3; 7 if (params != null) { 8 if (params.containsKey(KEY_PARAM_1) && params[KEY_PARAM_1] is int) { 9 pageNumberToDisplay = params[KEY_PARAM_1] as int; 10 } 11 } 12 return AppPage3(pageNumber: pageNumberToDisplay); 13 }; 14 15 final int pageNumber; 16 17 AppPage3({this.pageNumber}); 
 
 4 static RouteHandler pageHandler = 5 (BuildContext context, {Map<String, dynamic> params}) { 6 var pageNumberToDisplay = 3; 7 if (params != null) { 8 if (params.containsKey(KEY_PARAM_1) && params[KEY_PARAM_1] is int) { 9 pageNumberToDisplay = params[KEY_PARAM_1] as int; 10 } 11 } 12 return AppPage3(pageNumber: pageNumberToDisplay); 13 };
  55. Wywołanie 1 class AppPage2 extends StatelessWidget { [...] 12 onPressed:

    () { 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionPushNamed("/page3", params: { AppPage3.KEY_PARAM_1 : 10})); 1 class AppPage2 extends StatelessWidget { [...] 13 onPressed: () { 14 BlocProvider.of<NavigationBloc>(context) 15 .add(NavigatorActionPush((BuildContext context)=>AppPage3(20))); [...] params: { AppPage3.KEY_PARAM_1 : 10}));
  56. Wywołanie 1 class AppPage2 extends StatelessWidget { [...] 12 onPressed:

    () { 13 BlocProvider.of<NavigationBloc>(context) 14 .add(NavigatorActionPushNamed("/page3", params: { AppPage3.KEY_PARAM_1 : 10})); 1 class AppPage2 extends StatelessWidget { [...] 13 onPressed: () { 14 BlocProvider.of<NavigationBloc>(context) 15 .add(NavigatorActionPush((BuildContext context)=>AppPage3(20))); [...] params: { AppPage3.KEY_PARAM_1 : 10})); [...] 15 .add(NavigatorActionPush((BuildContext context)=>AppPage3(20)));
  57. Material App - Opcja 2 1 class MyApp extends StatelessWidget

    { 2 final GlobalKey<NavigatorState> _navigatorKey = GlobalKey(); 3 4 MyApp() { 5 RouteList.configureRoutes(Router.appRouter); 6 } 7 8 @override 9 Widget build(BuildContext context) { 10 return BlocProvider<NavigationBloc>( 11 create: (_) => NavigationBloc(navigatorKey: _navigatorKey), 12 child: MaterialApp( 13 navigatorKey: _navigatorKey, 14 home: AppPage1(), 15 title: 'Flutter Navigation Demo', 16 theme: getTheme(), 17 onGenerateRoute: Router.appRouter.generator, 18 )); 19 } 20 }
  58. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks
  59. 1 class PageForm extends StatefulWidget { 2 @override 3 State<StatefulWidget>

    createState() => _PageFormState(); 4 } 5 6 class _PageFormState extends State<PageForm> { 7 final _formKey = GlobalKey<FormState>(); 8 9 @override 10 Widget build(BuildContext context) { 11 return Scaffold( 12 appBar: AppBar( 13 title: Text("Login Page"), 14 ), 15 body: SafeArea( 16 child: Form( 17 key: _formKey, 18 child: Padding( 19 padding: const EdgeInsets.all(8.0), 20 child: Column( 21 crossAxisAlignment: CrossAxisAlignment.start, 22 children: <Widget>[
  60. 23 TextFormField( 24 validator: (value) { 25 if (value.isEmpty) {

    26 return 'Please enter some text'; 27 } 28 return null; 29 }, 30 ), 31 Padding( 32 padding: const EdgeInsets.symmetric(vertical: 16.0), 33 child: RaisedButton( 34 onPressed: () { 35 if (_formKey.currentState.validate()) { 36 BlocProvider.of<NavigationBloc>(context).add( 37 NavigatorActionReplaceHome( 38 (BuildContext context) => NewHomePage())); 39 } else { 40 Scaffold.of(context) 41 .showSnackBar(SnackBar(content: Text('Bad Data'))); 42 } 43 }, 44 child: Text('Submit'),
  61. 45 ), 46 ), 47 ], 48 ), 49 ),

    50 ), 51 ), 52 ); 53 } 54 }
  62. 45 ), 46 ), 47 ], 48 ), 49 ),

    50 ), 51 ), 52 ); 53 } 54 } https://iirokrankka.com/2018/06/18/putting-build-methods-on-a-diet/
  63. Zmiana ekranu "domowego": 1 enum NavigationType { 2 POP, 3

    PUSH, 4 HOME, 5 REPLACE_HOME 6 } 1 class NavigatorActionReplaceHome extends NavigatorAction { 2 final RouteHandler handler; 3 4 NavigatorActionReplaceHome(this.handler) 5 : super(navigationType: NavigationType.REPLACE_HOME); 6 } 1 case NavigationType.REPLACE_HOME: 2 final pushAction = event as NavigatorActionReplaceHome; 3 yield navigatorKey.currentState.pushAndRemoveUntil( 4 MaterialPageRoute(builder: pushAction.handler), (route) => false); 5 break;
  64. Zmiana ekranu "domowego": 1 enum NavigationType { 2 POP, 3

    PUSH, 4 HOME, 5 REPLACE_HOME 6 } 
 
 
 5 REPLACE_HOME 1 class NavigatorActionReplaceHome extends NavigatorAction { 2 final RouteHandler handler; 3 4 NavigatorActionReplaceHome(this.handler) 5 : super(navigationType: NavigationType.REPLACE_HOME); 6 } 1 case NavigationType.REPLACE_HOME: 2 final pushAction = event as NavigatorActionReplaceHome; 3 yield navigatorKey.currentState.pushAndRemoveUntil( 4 MaterialPageRoute(builder: pushAction.handler), (route) => false); 5 break;
  65. Zmiana ekranu "domowego": 1 enum NavigationType { 2 POP, 3

    PUSH, 4 HOME, 5 REPLACE_HOME 6 } 1 class NavigatorActionReplaceHome extends NavigatorAction { 2 final RouteHandler handler; 3 4 NavigatorActionReplaceHome(this.handler) 5 : super(navigationType: NavigationType.REPLACE_HOME); 6 } 1 case NavigationType.REPLACE_HOME: 2 final pushAction = event as NavigatorActionReplaceHome; 3 yield navigatorKey.currentState.pushAndRemoveUntil( 4 MaterialPageRoute(builder: pushAction.handler), (route) => false); 5 break;
  66. Zmiana ekranu "domowego": 1 enum NavigationType { 2 POP, 3

    PUSH, 4 HOME, 5 REPLACE_HOME 6 } 1 class NavigatorActionReplaceHome extends NavigatorAction { 2 final RouteHandler handler; 3 4 NavigatorActionReplaceHome(this.handler) 5 : super(navigationType: NavigationType.REPLACE_HOME); 6 } 1 case NavigationType.REPLACE_HOME: 2 final pushAction = event as NavigatorActionReplaceHome; 3 yield navigatorKey.currentState.pushAndRemoveUntil( 4 MaterialPageRoute(builder: pushAction.handler), (route) => false); 5 break;
  67. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks
  68. Nawigator 1 case NavigationType.PUSH: 2 final pushAction = event as

    NavigatorActionPush; 3 yield navigatorKey.currentState 4 .push(createAnimatedPageRoute(pushAction.handler)); 5 break; 6 case NavigationType.REPLACE_HOME: 7 final pushAction = event as NavigatorActionReplaceHome; 8 yield navigatorKey.currentState.pushAndRemoveUntil( 9 createAnimatedPageRoute(pushAction.handler), (route) => false); 10 break;
  69. Nawigator 1 Route<dynamic> createAnimatedPageRoute(RouteHandler handler) 2 { 3 return PageRouteBuilder<dynamic>(

    4 pageBuilder:(context, animation, secondaryAnimation) { 5 return handler(context); 6 }, 7 transitionDuration: Duration(milliseconds: 500), 8 transitionsBuilder: (context, animation, secondaryAnimation, child){ 9 return FadeTransition(opacity: animation, child: child); 10 }, 11 ); 12 } 
 3 return PageRouteBuilder<dynamic>( 4 pageBuilder:(context, animation, secondaryAnimation) { 5 return handler(context); 6 },
  70. Nawigator 1 Route<dynamic> createAnimatedPageRoute(RouteHandler handler) 2 { 3 return PageRouteBuilder<dynamic>(

    4 pageBuilder:(context, animation, secondaryAnimation) { 5 return handler(context); 6 }, 7 transitionDuration: Duration(milliseconds: 500), 8 transitionsBuilder: (context, animation, secondaryAnimation, child){ 9 return FadeTransition(opacity: animation, child: child); 10 }, 11 ); 12 } 7 transitionDuration: Duration(milliseconds: 500), 8 transitionsBuilder: (context, animation, secondaryAnimation, child){
  71. Nawigator 1 Route<dynamic> createAnimatedPageRoute(RouteHandler handler) 2 { 3 return PageRouteBuilder<dynamic>(

    4 pageBuilder:(context, animation, secondaryAnimation) { 5 return handler(context); 6 }, 7 transitionDuration: Duration(milliseconds: 500), 8 transitionsBuilder: (context, animation, secondaryAnimation, child){ 9 return FadeTransition(opacity: animation, child: child); 10 }, 11 ); 12 } 9 return FadeTransition(opacity: animation, child: child);
  72. Nawigator 1 Route<dynamic> createAnimatedPageRoute(RouteHandler handler) 2 { 3 return PageRouteBuilder<dynamic>(

    4 pageBuilder:(context, animation, secondaryAnimation) { 5 return handler(context); 6 }, 7 transitionDuration: Duration(milliseconds: 500), 8 transitionsBuilder: (context, animation, secondaryAnimation, child){ 9 return FadeTransition(opacity: animation, child: child); 10 }, 11 ); 12 } 9 return FadeTransition(opacity: animation, child: child);
  73. Nawigator 1 Route<dynamic> createAnimatedPageRoute(RouteHandler handler) 2 { 3 return PageRouteBuilder<dynamic>(

    4 pageBuilder:(context, animation, secondaryAnimation) { 5 return handler(context); 6 }, 7 transitionDuration: Duration(milliseconds: 500), 8 transitionsBuilder: (context, animation, secondaryAnimation, child){ 9 return SlideTransition( 10 position: Tween<Offset>( 11 begin: Offset(1.0, 0.0), 12 end: Offset(0.0, 0.0), 13 ).animate(animation), 14 child: child, 15 ); 16 }, 17 ); 18 } 9 return SlideTransition( 10 position: Tween<Offset>( 11 begin: Offset(1.0, 0.0), 12 end: Offset(0.0, 0.0), 13 ).animate(animation), 14 child: child,
  74. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks Założenie obsługa Bottom bara jest już spełniona. 
 Otrzymujemy 2 metody: 
 onRefreshTab onSelectTab
  75. Obsługa kilku nawigatorów 1 class NewHomePageState extends State<NewHomePage> { 2

    final GlobalKey<NavigatorState> _navigatorKey1 = GlobalKey(); 3 final GlobalKey<NavigatorState> _navigatorKey2 = GlobalKey(); 4 DashboardTabItem currentTab = DashboardTabItem.green; 5 6 @override 7 Widget build(BuildContext context) { 8 return Scaffold( 9 body: Stack( 10 children: <Widget>[ 11 _buildOffstageNavigator(DashboardTabItem.green), 12 _buildOffstageNavigator(DashboardTabItem.red), 13 _buildBody() 14 ], 15 ), 16 bottomNavigationBar: [...] 1 class NewHomePageState extends State<NewHomePage> { 2 final GlobalKey<NavigatorState> _navigatorKey1 = GlobalKey(); 3 final GlobalKey<NavigatorState> _navigatorKey2 = GlobalKey(); 4 DashboardTabItem currentTab = DashboardTabItem.green; 5 6 @override 7 Widget build(BuildContext context) { 8 return Scaffold( 9 body: Stack( 10 children: <Widget>[ 11 _buildOffstageNavigator(DashboardTabItem.green), 12 _buildOffstageNavigator(DashboardTabItem.red), 13 _buildBody() 14 ], 15 ), 16 bottomNavigationBar: [...]
  76. Obsługa kilku nawigatorów 1 class NewHomePageState extends State<NewHomePage> { 2

    final GlobalKey<NavigatorState> _navigatorKey1 = GlobalKey(); 3 final GlobalKey<NavigatorState> _navigatorKey2 = GlobalKey(); 4 DashboardTabItem currentTab = DashboardTabItem.green; 5 6 @override 7 Widget build(BuildContext context) { 8 return Scaffold( 9 body: Stack( 10 children: <Widget>[ 11 _buildOffstageNavigator(DashboardTabItem.green), 12 _buildOffstageNavigator(DashboardTabItem.red), 13 _buildBody() 14 ], 15 ), 16 bottomNavigationBar: [...] 2 final GlobalKey<NavigatorState> _navigatorKey1 = GlobalKey(); 3 final GlobalKey<NavigatorState> _navigatorKey2 = GlobalKey();
  77. Obsługa kilku nawigatorów 1 class NewHomePageState extends State<NewHomePage> { 2

    final GlobalKey<NavigatorState> _navigatorKey1 = GlobalKey(); 3 final GlobalKey<NavigatorState> _navigatorKey2 = GlobalKey(); 4 DashboardTabItem currentTab = DashboardTabItem.green; 5 6 @override 7 Widget build(BuildContext context) { 8 return Scaffold( 9 body: Stack( 10 children: <Widget>[ 11 _buildOffstageNavigator(DashboardTabItem.green), 12 _buildOffstageNavigator(DashboardTabItem.red), 13 _buildBody() 14 ], 15 ), 16 bottomNavigationBar: [...] 8 return Scaffold( 9 body: Stack( 10 children: <Widget>[ 11 _buildOffstageNavigator(DashboardTabItem.green), 12 _buildOffstageNavigator(DashboardTabItem.red), 13 _buildBody()
  78. Obsługa kilku nawigatorów 1 Widget _buildBody() { 2 return Offstage(

    3 offstage: currentTab != DashboardTabItem.settings, 4 child: AppPage25(), 5 ); 6 } 7 8 Widget _buildOffstageNavigator(DashboardTabItem tabItem) { 9 final navKey = 10 tabItem == DashboardTabItem.green ? _navigatorKey1 : _navigatorKey2; 11 final color = tabItem == DashboardTabItem.green ? Colors.green : Colors.red; 12 return Offstage( 13 offstage: currentTab != tabItem, 14 child: BlocProvider<NavigationBloc>( 15 create: (_) => NavigationBloc(navigatorKey: navKey), 16 child: MaterialApp( 17 navigatorKey: navKey, 18 home: ColorPage(color: color, version: 1)))); 19 } 1 Widget _buildBody() { 2 return Offstage( 3 offstage: currentTab != DashboardTabItem.settings, 4 child: AppPage25(), 5 ); 6 } 7 8 Widget _buildOffstageNavigator(DashboardTabItem tabItem) { 9 final navKey = 10 tabItem == DashboardTabItem.green ? _navigatorKey1 : _navigatorKey2; 11 final color = tabItem == DashboardTabItem.green ? Colors.green : Colors.red; 12 return Offstage( 13 offstage: currentTab != tabItem, 14 child: BlocProvider<NavigationBloc>( 15 create: (_) => NavigationBloc(navigatorKey: navKey), 16 child: MaterialApp( 17 navigatorKey: navKey, 18 home: ColorPage(color: color, version: 1)))); 19 }
  79. Obsługa kilku nawigatorów 1 Widget _buildBody() { 2 return Offstage(

    3 offstage: currentTab != DashboardTabItem.settings, 4 child: AppPage25(), 5 ); 6 } 7 8 Widget _buildOffstageNavigator(DashboardTabItem tabItem) { 9 final navKey = 10 tabItem == DashboardTabItem.green ? _navigatorKey1 : _navigatorKey2; 11 final color = tabItem == DashboardTabItem.green ? Colors.green : Colors.red; 12 return Offstage( 13 offstage: currentTab != tabItem, 14 child: BlocProvider<NavigationBloc>( 15 create: (_) => NavigationBloc(navigatorKey: navKey), 16 child: MaterialApp( 17 navigatorKey: navKey, 18 home: ColorPage(color: color, version: 1)))); 19 } 
 
 
 
 
 
 
 
 
 
 
 
 12 return Offstage( 13 offstage: currentTab != tabItem, 14 child: BlocProvider<NavigationBloc>( 15 create: (_) => NavigationBloc(navigatorKey: navKey), 16 child: MaterialApp( 17 navigatorKey: navKey, 18 home: ColorPage(color: color, version: 1)))); 19 }
  80. Używanie navigationKey 1 bottomNavigationBar: BottomNav( 2 currentTab: currentTab, 3 onRefreshTab:

    () { 4 if (currentTab == DashboardTabItem.red) { 5 BlocProvider.of<NavigationBloc>(_navigatorKey2.currentContext) 6 .add(NavigatorActionHome()); 7 } else if (currentTab == DashboardTabItem.green) { 8 BlocProvider.of<NavigationBloc>(_navigatorKey1.currentContext) 9 .add(NavigatorActionHome()); 10 } 11 }, 12 onSelectTab: (DashboardMenuItem newTab) { 13 setState(() { 14 currentTab = newTab.tabItem; 15 }); 16 }, 17 ), 
 
 
 
 BlocProvider.of<NavigationBloc>(_navigatorKey2.currentContext) 6 .add(NavigatorActionHome()); 
 
 
 
 
 
 
 
 
 
 

  81. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks
  82. 1 return TabBarView( 2 children: myTabs.map((Tab tab) { 3 MyScrollableTabView(

    4 key: PageStorageKey<String>(tab.text), 5 tab: tab, 6 ), 7 }) 8 ); https://api.flutter.dev/flutter/widgets/PageStorageKey-class.html
  83. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks
  84. Zapisanie ścieżki 1 class NavObserver extends RouteObserver<CustomPageRouteBuilder> { 2 Queue<String>

    currentStack = Queue(); 3 final String navKey; 4 5 NavObserver(this.navKey); 6 7 @override 8 void didStopUserGesture() {} 9 10 void _printStack(String command) { 11 var value = "/"; 12 for (int i = 0; i < currentStack.length; ++i) { 13 value += currentStack.elementAt(i) + "/"; 14 } 15 print("[$navKey] = current stack after $command is : $value"); 16 } 17 18 @override 19 void didStartUserGesture( 20 Route<dynamic> route, Route<dynamic> previousRoute) {} 21 22 @override 23 void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) { 24 print("[$navKey] = DID REPLACE"); 1 class NavObserver extends RouteObserver<CustomPageRouteBuilder> {
  85. Zapisanie ścieżki 1 class NavObserver extends RouteObserver<CustomPageRouteBuilder> { 2 Queue<String>

    currentStack = Queue(); 3 final String navKey; 4 5 NavObserver(this.navKey); 6 7 @override 8 void didStopUserGesture() {} 9 10 void _printStack(String command) { 11 var value = "/"; 12 for (int i = 0; i < currentStack.length; ++i) { 13 value += currentStack.elementAt(i) + "/"; 14 } 15 print("[$navKey] = current stack after $command is : $value"); 16 } 17 18 @override 19 void didStartUserGesture( 20 Route<dynamic> route, Route<dynamic> previousRoute) {} 21 22 @override 23 void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) { 24 print("[$navKey] = DID REPLACE"); 10 void _printStack(String command) { 11 var value = "/"; 12 for (int i = 0; i < currentStack.length; ++i) { 13 value += currentStack.elementAt(i) + "/"; 14 } 15 print("[$navKey] = current stack after $command is : $value"); 16 }
  86. Zapisanie ścieżki 1 class NavObserver extends RouteObserver<CustomPageRouteBuilder> { 2 Queue<String>

    currentStack = Queue(); 3 final String navKey; 4 5 NavObserver(this.navKey); 6 7 @override 8 void didStopUserGesture() {} 9 10 void _printStack(String command) { 11 var value = "/"; 12 for (int i = 0; i < currentStack.length; ++i) { 13 value += currentStack.elementAt(i) + "/"; 14 } 15 print("[$navKey] = current stack after $command is : $value"); 16 } 17 18 @override 19 void didStartUserGesture( 20 Route<dynamic> route, Route<dynamic> previousRoute) {} 21 22 @override 23 void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) { 24 print("[$navKey] = DID REPLACE"); 2 Queue<String> currentStack = Queue(); 3 final String navKey; 4 5 NavObserver(this.navKey);
  87. Zapisanie ścieżki 1 class NavObserver extends RouteObserver<CustomPageRouteBuilder> { [...] 22

    @override 23 void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) { 24 print("[$navKey] = DID REPLACE"); 25 if (newRoute is CustomPageRouteBuilder) { 26 //simple version 27 currentStack.clear(); 28 currentStack.add(newRoute.name); 29 _printStack("didReplace"); 30 } 31 } 32 33 @override 34 void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { 35 if (route is CustomPageRouteBuilder) { 36 currentStack.removeWhere((element) => element == route.name); 37 _printStack("didRemove"); 38 } 39 } 40 41 @override 42 void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { 43 if (route is CustomPageRouteBuilder) { 44 currentStack.removeLast(); 23 void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
  88. Zapisanie ścieżki 1 class NavObserver extends RouteObserver<CustomPageRouteBuilder> { [...] 22

    @override 23 void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) { 24 print("[$navKey] = DID REPLACE"); 25 if (newRoute is CustomPageRouteBuilder) { 26 //simple version 27 currentStack.clear(); 28 currentStack.add(newRoute.name); 29 _printStack("didReplace"); 30 } 31 } 32 33 @override 34 void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { 35 if (route is CustomPageRouteBuilder) { 36 currentStack.removeWhere((element) => element == route.name); 37 _printStack("didRemove"); 38 } 39 } 40 41 @override 42 void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { 43 if (route is CustomPageRouteBuilder) { 44 currentStack.removeLast(); 34 void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { 35 if (route is CustomPageRouteBuilder) { 36 currentStack.removeWhere((element) => element == route.name); 37 _printStack("didRemove"); 38 } 39 }
  89. Zapisanie ścieżki 29 _printStack("didReplace"); 30 } 31 } 32 33

    @override 34 void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { 35 if (route is CustomPageRouteBuilder) { 36 currentStack.removeWhere((element) => element == route.name); 37 _printStack("didRemove"); 38 } 39 } 40 41 @override 42 void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { 43 if (route is CustomPageRouteBuilder) { 44 currentStack.removeLast(); 45 _printStack("didPop"); 46 } 47 } 48 49 @override 50 void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { 51 if (route is CustomPageRouteBuilder) { 52 currentStack.add(route.name); 53 _printStack("didPush"); 54 } 55 } 56 } 41 @override 42 void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { 43 if (route is CustomPageRouteBuilder) { 44 currentStack.removeLast(); 45 _printStack("didPop"); 46 } 47 }
  90. Zapisanie ścieżki 29 _printStack("didReplace"); 30 } 31 } 32 33

    @override 34 void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { 35 if (route is CustomPageRouteBuilder) { 36 currentStack.removeWhere((element) => element == route.name); 37 _printStack("didRemove"); 38 } 39 } 40 41 @override 42 void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { 43 if (route is CustomPageRouteBuilder) { 44 currentStack.removeLast(); 45 _printStack("didPop"); 46 } 47 } 48 49 @override 50 void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { 51 if (route is CustomPageRouteBuilder) { 52 currentStack.add(route.name); 53 _printStack("didPush"); 54 } 55 } 56 } 49 @override 50 void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { 51 if (route is CustomPageRouteBuilder) { 52 currentStack.add(route.name); 53 _printStack("didPush"); 54 } 55 } 56 }
  91. Plan • Projekt nawigatora • Przekazywanie parametrów (2 sposoby) •

    Przykład z ekranem logowania • Animacje przejść • Zagnieżdżenie nawigacji • Utrzymywanie danych i nawigatora pomiędzy uruchomieniami • Tips & tricks
  92. Przekazanie rezultatu 1 final result = await Navigator.of(context).push<MaterialPageRoute<bool>>(...) 2 if

    (result == null) { 3 print("Użytkownik się cofnął") 4 } 5 else { 6 print("Wykonano Navigator.of(context).pop(true)") 7 }
  93. Obsługa "back button" 1 switch (event.navigationType) { 2 case NavigationType.POP:

    3 yield navigatorKey.currentState.pop(); 4 break; 1 yield navigatorKey.currentState.maybePop(); 1 switch (event.navigationType) { 2 case NavigationType.POP: 3 yield navigatorKey.currentState.pop(); 4 break; 1 @override 2 Widget build(BuildContext context) { 3 return WillPopScope( 4 onWillPop: () async { BlocProvider.of<NavigationBloc>(context).
 add(NavigatorActionPop()); 6 return Future(()=>true); 7 } 8 child: new Scaffold(); 9 }
  94. Obsługa "back button" 1 switch (event.navigationType) { 2 case NavigationType.POP:

    3 yield navigatorKey.currentState.pop(); 4 break; 1 yield navigatorKey.currentState.maybePop(); 3 yield navigatorKey.currentState.pop(); 1 @override 2 Widget build(BuildContext context) { 3 return WillPopScope( 4 onWillPop: () async { BlocProvider.of<NavigationBloc>(context).
 add(NavigatorActionPop()); 6 return Future(()=>true); 7 } 8 child: new Scaffold(); 9 }
  95. Obsługa "back button" 1 switch (event.navigationType) { 2 case NavigationType.POP:

    3 yield navigatorKey.currentState.pop(); 4 break; 1 yield navigatorKey.currentState.maybePop(); 3 yield navigatorKey.currentState.pop(); 1 @override 2 Widget build(BuildContext context) { 3 return WillPopScope( 4 onWillPop: () async { BlocProvider.of<NavigationBloc>(context).
 add(NavigatorActionPop()); 6 return Future(()=>true); 7 } 8 child: new Scaffold(); 9 }
  96. Obsługa "back button" 1 switch (event.navigationType) { 2 case NavigationType.POP:

    3 yield navigatorKey.currentState.pop(); 4 break; 1 yield navigatorKey.currentState.maybePop(); 3 yield navigatorKey.currentState.pop(); 1 @override 2 Widget build(BuildContext context) { 3 return WillPopScope( 4 onWillPop: () async { BlocProvider.of<NavigationBloc>(context).
 add(NavigatorActionPop()); 6 return Future(()=>true); 7 } 8 child: new Scaffold(); 9 }
  97. Częste problemy - Warning: When using initialRoute, don’t define a

    home property. 1 @override 2 Widget build(BuildContext context) { 3 return BlocProvider<NavigationBloc>( 4 create: (_) => NavigationBloc(navigatorKey: _navigatorKey), 5 child: MaterialApp( 6 navigatorKey: _navigatorKey, 7 initialRoute: "/", 8 title: 'Flutter Navigation Demo', 9 theme: getTheme(),
 10 home: AppPage1(), 11 onGenerateRoute: Router.appRouter.generator,));}
  98. Częste problemy 1 @override 2 bool canTransitionTo(TransitionRoute<dynamic> nextRoute) { 3

    // Don't perform outgoing animation if the next route is a fullscreen dialog. 4 return (nextRoute is MaterialPageRoute && ! nextRoute.fullscreenDialog) 5 || (nextRoute is CupertinoPageRoute && ! nextRoute.fullscreenDialog); 6 }
  99. Dialog na nowym ekranie 1 void initState() { 2 super.initState();

    3 WidgetsBinding.instance 4 .addPostFrameCallback((_) => afterFirstLayout(context)); 5 }
  100. Sens użycia BLoC-a do nawigacji • Kod łączący kontrolowanie logiki

    biznesowej i UI jest tym, czego próbujemy uniknąć. (Niestety czasami przejścia są kontrolowane przez logikę biznesową) • Brak BuildContext-u • Łatwość testowania skomplikowanych sekwencji ekranów • Scentralizowana nawigacja • Świadomość stanu nawigacji! UI BLoC Strumień Strumień UI BLoC Wywołania Strumień • Rozwiązaniem może być "Simple BLoC". (Zastępujemy zdarzenia prostymi wywołaniami)
  101. Dialogi 1 push(MobileRoute( 2 child: this, 3 theme: Theme.of(context), 4

    barrierDismissible: dismissable, 5 settings: ... 6 )); 
 
 MobileRoute<T> extends PopupRoute<T>
  102. Deep Link • Własne schematy URL [ANDROID: Deep Links, iOS:

    Custom URL schemes] (schemat://jakiś link)
 Firebase Dynamic Links, uni-links • Uniwersalne linki [ANDROID: app links, iOS: Universal Links] (https://host)
  103. Deep Link Android iOS Method Channel (NATIVE) Method Channel (NATIVE)

    Flutter BLoC Deep Link Link: 
 sample.deeplink.flutter.dev/open metoda: add nawigator