You can get everything (paths, parameters, etc) from onGenerateRoute
. Your Home
will be /
and everything from there can be grabbed and used to redirect users.
My approach to solve this is the following. Your base App()
should be like:
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Website Title',
onGenerateRoute: (settings) => NavigatorRoute.route(settings.name),
);
}
}
and the class NavigatorRoute
will be:
class NavigatorRoute extends StatefulWidget {
final String path;
static Route<dynamic> route(String path) {
return SimpleRoute(
name: '', // this one is always empty as you didn't route yet
title: 'Website Title',
builder: (_) => NavigatorRoute(path: path),
animated: false
);
}
const NavigatorRoute({Key key, this.path}) : super(key: key);
@override
_NavigatorRouteState createState() => _NavigatorRouteState();
}
class _NavigatorRouteState extends State<NavigatorRoute> {
@override
void initState() {
super.initState();
Future.microtask(() {
if (widget.path == '/') {
Navigator.of(context).pushAndRemoveUntil(HomeScreen.route(false), (_) => false);
return;
} else if (widget.path == '/user') {
Navigator.of(context).pushAndRemoveUntil(UserScreen.route(false), (_) => false);
return;
} else if (widget.path.contains('/user/')) {
Navigator.of(context).pushAndRemoveUntil(UserScreen.routeCode(widget.path.split('/')[2]), (_) => false);
return;
} else if (widget.path == '/about') {
Navigator.of(context).pushAndRemoveUntil(AboutScreen.route(), (_) => false);
return;
} else {
Navigator.of(context).pushAndRemoveUntil(HomeScreen.route(), (_) => false);
return;
}
});
}
@override
Widget build(BuildContext context) {
return SizedBox();
}
}
The code for the SimpleRoute
is:
class SimpleRoute extends PageRoute {
SimpleRoute({@required String name, @required this.title, @required this.builder, @required this.animated})
: super(settings: RouteSettings(name: name));
final String title;
final WidgetBuilder builder;
final bool animated;
@override
Color get barrierColor => null;
@override
String get barrierLabel => null;
@override
bool get maintainState => true;
@override
Duration get transitionDuration => Duration(milliseconds: 200);
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return animated
? FadeTransition(
opacity: animation,
child: Title(
title: this.title,
color: Theme.of(context).primaryColor,
child: builder(context),
),
)
: Title(
title: this.title,
color: Theme.of(context).primaryColor,
child: builder(context),
);
}
}
So, finally... if you want to easily open one of your screens, you can do:
class HomeScreen extends StatefulWidget {
static Route<dynamic> route(bool animated) {
return SimpleRoute(name: '/', title: 'Home', builder: (_) => HomeScreen(), animated: animated);
}
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
...
}
The routeCode
could be:
static Route<dynamic> routeCode(String id) {
return SimpleRoute(name: '/user/$id', title: 'User', builder: (_) => UserScreen(id: id), animated: false);
}
The main benefit of doing this is avoiding the stack of pages generated by accessing the last screen.
For example, if you're using directly the onGenerateRoute
for "www.mywebsite.com/user/userId/edit" then Flutter will open:
- Home Screen
- User Screen
- UserId Screen
- Edit Screen
but with this approach, only "Edit Screen" will be open.