Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to open new MaterialPageRoute as a child in widget tree in Flutter

In the example below when I push new MaterialPageRoute it is created on the same level as Home widget in the Flutter widget tree. I would like to have it as a child of widget Home, so Home would be a parent of Child widget.

Here is a full code:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Home(),
  ));
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Center(
            child: Text("This is home"),
          ),
          RaisedButton(
            child: Text("Open child view"),
            onPressed: () {
              Navigator.of(context)
                  .push(MaterialPageRoute(builder: (context) => Child()));
            },
          )
        ],
      ),
    );
  }
}

class Child extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
      child: Text("Child view"),
    ));
  }
}

Here is how the widget tree looks like

enter image description here

I want to achieve that because I would like to initialize the ScopedModel in Home widget and have it available in every new MaterialPageRoute I create.

like image 1000
mbartn Avatar asked Apr 20 '20 19:04

mbartn


People also ask

How do you call parent function from child widget in Flutter?

To call a function of a parent, you can use the callback pattern. In this example, a function on the color selected is passed to the child. The child calls the function when a button is pressed: import 'package:flutter/material.

How do you add children in Column in Flutter?

You can add multiple children it's simple like below example: Column( children: <Widget>[ Container( padding: EdgeInsets. only(left: 40, top: 0), child: new Image. asset('assets/images/blue_dot.


2 Answers

Navigator.of(context).push() will replace your Home screen with a new screen (while keeping the Home screen in memory so you can go back to it). They are on the same level in the widget tree, the only way to nest them is to use nested Navigators I think.

But, given what you want to achieve: why not initialize the ScopedModel one level up and provide at the root of your widget tree? That way you can access your model both in the Home screen as well as the Child screen.

Below is how you could do that, I added a simple ScopedModel and am able to access it's textproperty inside the Child screen.

import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import 'package:tryout/model.dart';

void main() {
  runApp(
    ScopedModel<TestModel>(
      model: TestModel(),
      child: MaterialApp(
        home: Home(),
      ),
    )
  );
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Center(
            child: Text("This is home"),
          ),
          RaisedButton(
            child: Text("Open child view"),
            onPressed: () {
              Navigator.of(context)
                  .push(MaterialPageRoute(builder: (context) => Child()));
            },
          )
        ],
      ),
    );
  }
}

class Child extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
      child: Text("${ScopedModel.of<TestModel>(context).text}"),
    ));
  }
}

And here's the TestModel class:

import 'package:scoped_model/scoped_model.dart';

class TestModel extends Model {
  String _text = "Test to see if this works!";
  String get text => _text;
}
like image 169
JJuice Avatar answered Oct 01 '22 03:10

JJuice


I solved my issue using nested Navigator.

Here is the example:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Home(),
  ));
}

var homeNavigatorKey = GlobalKey<NavigatorState>();

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Navigator(
        key: homeNavigatorKey,
        onGenerateRoute: (settings) {
          /*dirty code for illustration purposes only*/
          if (settings.name == '/child') {
            return MaterialPageRoute(builder: (context) => Child());
          } else {
            return MaterialPageRoute(
                builder: (context) => Column(
                      children: <Widget>[
                        Center(
                          child: Text("This is home"),
                        ),
                        RaisedButton(
                          child: Text("Open child view"),
                          onPressed: () {
                            homeNavigatorKey.currentState.pushNamed('/child');
                          },
                        )
                      ],
                    ));
          }
        },
      ),
    );
  }
}

class Child extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
      child: RaisedButton(
        onPressed: () => Navigator.of(context).pop(),
        child: Text("Back to home"),
      ),
    ));
  }
}

The tree looks like this

enter image description here

and allows for passing data from Home to every child.

Feel free to comment or post answers if you have any simpler solution.

like image 36
mbartn Avatar answered Oct 01 '22 03:10

mbartn