I'm having still no success with my Flutter Web App, doing an URL based routing and keeping things like the appbar and the drawer persistent.
The goal I'm trying to achieve is, that I can only modify the content of my App. So i.e. if the user enters the url $baseurl/#/ it should navigate to the content of page one. $baseurl/#/two to the content of page two, and so on...
My main file is something like this. As you can see it's done with Fluro Router and I tried so simplify everything to see my main goal.
import 'package:flutter/material.dart';
import 'package:newnavigationtest/routes.dart';
void main() {
FluroRouter.setupRouter();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MainLayout(),
);
}
}
class MainLayout extends StatelessWidget {
final navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
Column(
children: [
Expanded(
child: Container(
color: Colors.green,
width: 100,
child: Text("Static sidebar"),
),
),
],
),
Expanded(
child: Navigator(
key: navigatorKey,
initialRoute: '/',
onGenerateRoute: FluroRouter.router.generator,
),
)
],
),
);
}
}
The FluroRouter file looks like this
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
class FluroRouter {
static Router router = Router();
static Handler _routeOneHandler = Handler(
handlerFunc: (BuildContext context, Map<String, dynamic> params) =>
Container(child: Center(child: Text("Later content for page 1"))));
static Handler _routeTwoHandler = Handler(
handlerFunc: (BuildContext context, Map<String, dynamic> params) =>
Container(child: Center(child: Text("Later content for page 2"))));
static void setupRouter() {
router.define(
'/',
handler: _routeOneHandler,
);
router.define(
'/two',
handler: _routeTwoHandler,
);
}
}
Clearly, if the user enters a URL nothing happens at the moment. I think this is because the main navigator in the MaterialApp is consuming the input from the user and not passing it through to my Navigator in the Scaffold. But I'm absolutely not sure.
Can anybody point me the right way to achieve the wanted behavior?
Thanks!
Update 1:
I also tried something like using the builder to build the child and keep the rest persistent. (This leads me to the behavior I'm looking for, except for the OverLay Error)
import 'package:flutter/material.dart';
import 'package:newnavigationtest/routes.dart';
void main() {
FluroRouter.setupRouter();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
key: navigatorKey,
initialRoute: '/',
onGenerateRoute: FluroRouter.router.generator,
builder: (context, child) {
return MainLayout(child: child);
},
);
}
}
class MainLayout extends StatelessWidget {
final Widget child;
MainLayout({@required this.child});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
Column(
children: [
Expanded(
child: Container(
color: Colors.green,
width: 100,
child:
Tooltip(message: "Hello", child: Text("Static sidebar")),
),
),
],
),
Expanded(
child: child,
)
],
),
);
}
}
But this leads to a missing Overlay at the tooltip.
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building Tooltip("Hello", dirty, state: _TooltipState#93c0f(ticker inactive)):
No Overlay widget found.
Tooltip widgets require an Overlay widget ancestor for correct operation.
It can be opened via swipe gesture or by clicking on the menu icon in the app bar. Typically, the navigation drawer opens up from the left side of the screen, but you can also configure it to open from the right side (for the LTR text settings).
To share a drawer between all pages we could add a builder in our MaterialApp instance. This will instantiate a Scaffold under Navigator but above all routes. Inside your page, you can instantiate another Scaffold without restriction as you'd usually do.
You have your own custom Menu button to open/close drawer. You don't want to use AppBar as well. In that case you can use GlobalKey<ScaffoldState>() object to open Drawer.
Because Fluro redirects without persistence, you may have to have each page have a Scaffold with an AppBar and Drawer, most efficient way would to have a custom scaffold you could re-use.
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
void main() {
FluroRouter.setupRouter();
runApp(
MaterialApp(
title: 'Your website',
onGenerateRoute: FluroRouter.router.generator
),
);
}
class CustomScaffold extends StatelessWidget {
final Widget body;
CustomScaffold({this.body});
@override
Widget build(BuildContext context) {
return Scaffold(
//your appbar here
appBar: AppBar(),
//your drawer here
drawer: Drawer(),
body: body,
);
}
}
class FluroRouter {
static Router router = Router();
static Handler _routeOneHandler = Handler(
handlerFunc: (BuildContext context, Map<String, dynamic> params) => PageOne());
static Handler _routeTwoHandler = Handler(
handlerFunc: (BuildContext context, Map<String, dynamic> params) => PageTwo());
static void setupRouter() {
router.define(
'/',
handler: _routeOneHandler,
);
router.define(
'/two',
handler: _routeTwoHandler,
);
}
}
class PageOne extends StatelessWidget {
Widget build(BuildContext context) {
return CustomScaffold(
body: Container(child: Text('Page 1')),
);
}
}
class PageTwo extends StatelessWidget {
Widget build(BuildContext context) {
return CustomScaffold(
body: Container(child: Text('Page 2')),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With