Skip to content

Instantly share code, notes, and snippets.

@Sandfone
Last active March 24, 2021 08:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Sandfone/bf810e6de3156553a15e9db473934167 to your computer and use it in GitHub Desktop.
Save Sandfone/bf810e6de3156553a15e9db473934167 to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: MyRouteInformationParser(),
routerDelegate: MyRouterDelegate(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Home"
),
),
body: Center(
child: Text(
"this is home page"
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
),
onPressed: () {
MyRouterDelegate.of(context).pushNamed("/first");
},
),
);
}
}
class MyRouteInformationParser extends RouteInformationParser<RouteSettings> {
@override
Future<RouteSettings> parseRouteInformation(RouteInformation routeInformation) {
print("name: ${routeInformation.location}");
return SynchronousFuture(RouteSettings(
name: routeInformation.location
));
}
}
class MyRouterDelegate extends RouterDelegate<RouteSettings>
with ChangeNotifier {
MyRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();
final _pages = <MyPage>[];
final GlobalKey<NavigatorState> navigatorKey;
static MyRouterDelegate of(BuildContext context) {
RouterDelegate routerDelegate = Router.of(context).routerDelegate;
assert(routerDelegate is MyRouterDelegate);
return routerDelegate as MyRouterDelegate;
}
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: List.of(_pages),
onPopPage: (route, result) {
if (_pages.length > 1 && route.settings is MyPage) {
final MyPage<dynamic>? removed = _pages.lastWhere(
(element) => element.name == route.settings.name,
);
if (removed != null) {
_pages.remove(removed);
notifyListeners();
}
}
return route.didPop(result);
},
);
}
@override
Future<bool> popRoute() {
print("popRoute");
final NavigatorState? navigator = navigatorKey.currentState;
if (navigator == null)
return SynchronousFuture<bool>(false);
return navigator.maybePop();
}
@override
Future<void> setNewRoutePath(configuration) {
print("setNewRoutePath");
_pages.add(getRoutePage(
name: configuration.name!,
arguments: configuration.arguments as Map<String, dynamic>?));
return SynchronousFuture<void>(null);
}
Future<T?> pushNamed<T extends Object?>(String routeName, {
Map<String, dynamic>? arguments,
}) {
print("pushNamed: routeName: $routeName");
MyPage<T?> page = getRoutePage(name: routeName, arguments: arguments);
_pages.add(page);
notifyListeners();
return page.popped;
}
MyPage<T?> getRoutePage<T extends Object?>({
required String name,
Map<String, dynamic>? arguments,
}) {
MyRouteSettings routeSettings = getRouteSettings(name: name, arguments: arguments);
MyPage<T?> page = MyPage(
key: UniqueKey(),
name: routeSettings.name ?? '',
widget: routeSettings.widget ?? Container(),
arguments: routeSettings.arguments);
return page;
}
}
class MyRouteSettings extends RouteSettings {
const MyRouteSettings({
required String name,
Object? arguments,
this.widget,
this.showStatusBar,
this.routeName,
// this.pageRouteType,
// this.description,
// this.exts,
}) : super(
name: name,
arguments: arguments,
);
/// The Widget base on this route
final Widget? widget;
/// Whether show status bar.
final bool? showStatusBar;
/// The route name to track page
final String? routeName;
}
class MyPage<T> extends Page<T> {
MyPage({
required String name,
required LocalKey key,
required this.widget,
Object? arguments,
// this.showStatusBar,
// this.routeName,
// this.pageRouteType,
// this.description,
// this.exts,
}) : super(
key: key,
name: name,
arguments: arguments,
);
final Widget widget;
Future<T> get popped => _popCompleter.future;
final Completer<T> _popCompleter = Completer<T>();
bool get isCompleted => _popCompleter.isCompleted;
@override
Route<T> createRoute(BuildContext context) {
final Route<T> route = MaterialPageRoute(
settings: this,
builder: (BuildContext context) => widget,
);
return route
..popped.then((T? value) {
if (!isCompleted) {
_popCompleter.complete(value);
}
});
}
}
MyRouteSettings getRouteSettings ({
required String name,
Map<String, dynamic>? arguments,
}) {
final Map<String, dynamic> safeArguments =
arguments ?? const <String, dynamic>{};
switch (name) {
case '/':
return MyRouteSettings(
name: name,
arguments: arguments,
widget: MyHomePage(),
);
case '/first':
return MyRouteSettings(
name: name,
arguments: arguments,
widget: FirstPage(),
);
case '/second':
return MyRouteSettings(
name: name,
arguments: arguments,
widget: SecondPage(),
);
default:
return const MyRouteSettings(name: '404');
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"First Page"
),
),
body: Center(
child: Text(
"this is the first page"
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.arrow_circle_up,
),
onPressed: () {
},
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Second Page"
),
),
body: Center(
child: Text(
"this is the second page"
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment