Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter for web routing with multiple material apps

I have an issue regarding the routing of the flutter for the web. For specific reasons in my project, I have multiple material apps. So the platform that I'm building is a material app, let's name it 'Parent'. In this material app at some point lower in the widget tree I have a child that is also a material app let's name it 'Child'. When the user arrives at the point in the Parent tree where Child is rendered, it looks like the routing of Parent is replaced with the actual routing of Child. Is there any way to prevent this from happening?

Since I can't share the actual code I've recreated a minimal example:

import 'package:flutter/material.dart';

void main() {
  runApp(ParentApp());
}

class ParentApp extends StatefulWidget {
  @override
  _ParentAppState createState() => _ParentAppState();
}

class _ParentAppState extends State<ParentApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Parent',
      initialRoute: '/parent-home',
      routes: {
        '/parent-home': (context) => ParentHome(),
        '/parent-second': (context) => ParentSecondRoute(),
      },
    );
  }
}

class ParentHome extends StatefulWidget {
  @override
  _ParentHomeState createState() => _ParentHomeState();
}

class _ParentHomeState extends State<ParentHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      body: Container(
        child: Center(
          child: RaisedButton(
            child: Text('Go to second route'),
            onPressed: () => Navigator.pushNamed(
              context,
              '/parent-second',
            ),
          ),
        ),
      ),
    );
  }
}

class ParentSecondRoute extends StatefulWidget {
  @override
  _ParentSecondRouteState createState() => _ParentSecondRouteState();
}

class _ParentSecondRouteState extends State<ParentSecondRoute> {
  bool isChildRendered;

  @override
  void initState() {
    isChildRendered = false;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Flexible(
            child: isChildRendered
                ? ChildApp()
                : Container(
                    color: Colors.green,
                    child: Center(
                      child: RaisedButton(
                        child: Text('Go to home'),
                        onPressed: () => Navigator.of(context).pop(),
                      ),
                    ),
                  ),
          ),
          Flexible(
            child: Center(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Checkbox(
                    value: isChildRendered,
                    onChanged: (value) => setState(() {
                      isChildRendered = value;
                    }),
                  ),
                  SizedBox(width: 5),
                  Text('Is child rendered?'),
                ],
              ),
            ),
          )
        ],
      ),
    );
  }
}

class ChildApp extends StatefulWidget {
  @override
  _ChildAppState createState() => _ChildAppState();
}

class _ChildAppState extends State<ChildApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Child',
      initialRoute: '/child-route-i-don\'t-want-to-see',
      routes: {
        '/child-route-i-don\'t-want-to-see': (context) => Container(
              color: Colors.brown,
            ),
      },
    );
  }
}
like image 749
Iosif Pop Avatar asked Nov 25 '25 19:11

Iosif Pop


1 Answers

Solution with ModalRoute Class

You can solve it this way, by using the ModalRoute Class and passing the current route name defined in its settings as parameter to the Child:

ChildApp(ModalRoute.of(context).settings.name)

class ChildApp extends StatefulWidget {
  final String route;

  const ChildApp(this.route);
  @override
  _ChildAppState createState() => _ChildAppState();
}

class _ChildAppState extends State<ChildApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Child',
      initialRoute: widget.route,
      routes: {
        widget.route: (context) => Container(
          color: Colors.brown,
        ),
      },
    );
  }
}

name → String? The name of the route (e.g., "/settings"). [...]


Full example below:

import 'package:flutter/material.dart';

void main() {
  runApp(ParentApp());
}

class ParentApp extends StatefulWidget {
  @override
  _ParentAppState createState() => _ParentAppState();
}

class _ParentAppState extends State<ParentApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Parent',
      initialRoute: '/parent-home',
      routes: {
        '/parent-home': (context) => ParentHome(),
        '/parent-second': (context) => ParentSecondRoute(),
      },
    );
  }
}

class ParentHome extends StatefulWidget {
  @override
  _ParentHomeState createState() => _ParentHomeState();
}

class _ParentHomeState extends State<ParentHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      body: Container(
        child: Center(
          child: RaisedButton(
            child: Text('Go to second route'),
            onPressed: () => Navigator.pushNamed(
              context,
              '/parent-second',
            ),
          ),
        ),
      ),
    );
  }
}

class ParentSecondRoute extends StatefulWidget {
  @override
  _ParentSecondRouteState createState() => _ParentSecondRouteState();
}

class _ParentSecondRouteState extends State<ParentSecondRoute> {
  bool isChildRendered;

  @override
  void initState() {
    isChildRendered = false;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Flexible(
            child: isChildRendered
                ? ChildApp(ModalRoute.of(context).settings.name) // this line
                : Container(
              color: Colors.green,
              child: Center(
                child: RaisedButton(
                  child: Text('Go to home'),
                  onPressed: () => Navigator.of(context).pop(),
                ),
              ),
            ),
          ),
          Flexible(
            child: Center(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Checkbox(
                    value: isChildRendered,
                    onChanged: (value) => setState(() {
                      isChildRendered = value;
                    }),
                  ),
                  SizedBox(width: 5),
                  Text('Is child rendered?'),
                ],
              ),
            ),
          )
        ],
      ),
    );
  }
}

class ChildApp extends StatefulWidget {
  final String route;

  const ChildApp(this.route); // and this one
  @override
  _ChildAppState createState() => _ChildAppState();
}

class _ChildAppState extends State<ChildApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Child',
      initialRoute: widget.route,
      routes: {
        widget.route: (context) => Container(
          color: Colors.brown,
        ),
      },
    );
  }
}

Home

enter image description here

Second Route

enter image description here enter image description here

like image 159
Antonin GAVREL Avatar answered Nov 27 '25 08:11

Antonin GAVREL



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!