6

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.
Aerofluxx
  • 61
  • 1
  • 6

1 Answers1

1

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')),
    );
  }
}
Jackson Lee
  • 1,198
  • 4
  • 12
  • thanks! This is already a nice take on the problem but this will also rebuild the whole scaffold on every page switch. So I would need an option where the body is rather injected and not build with a returned CustomScaffold. Any further ideas? Thanks! :) – Aerofluxx May 18 '20 at 07:14
  • You could use a tab view, but you can't direct a URL into a dependent widget - Only Pages – Jackson Lee May 23 '20 at 01:46
  • You could direct a to a Scaffold with different parameters to show different content, problem is the url is being routed, which means its loading a new "Page" – Jackson Lee May 23 '20 at 01:55