简体   繁体   中英

How to solve navigator problem on flutter?

I'm trying to make the other page with the button but after debugging this code, the button called 'Next' appears but when I click the button, nothing happens and this error comes in "Navigator operation requested with a context that does not include a Navigator." Could someone help me out? Thank you a lot:)

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  TextEditingController nameController = TextEditingController();
  TextEditingController ageController = TextEditingController();
  TextEditingController addressController = TextEditingController();
  TextEditingController weightController = TextEditingController();
  TextEditingController heightController = TextEditingController();
  TextEditingController traitController = TextEditingController();
  TextEditingController appearanceController = TextEditingController();

  String fullName = '';
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.pink,
      ),
      home: Scaffold(
          appBar: AppBar(
            title: Text('Input Information'),
          ),
          drawer: Drawer(
            child: ListView(
              padding: EdgeInsets.zero,
              children: <Widget>[
                DrawerHeader(
                  child: Text('Drawer Header'),
                  decoration: BoxDecoration(
                    color: Colors.purple,
                  ),
                ),
                ListTile(
                  title: Text('Item 1'),
                  onTap: () {
                    Navigator.pop(context);
                  },
                ),
                ListTile(
                  title: Text('Item 2'),
                  onTap: () {
                    Navigator.pop(context);
                  },
                ),
              ],
            ),
          ),
          body: Center(
              child: Column(children: <Widget>[
            Container(
                margin: EdgeInsets.all(20),
                child: TextField(
                  controller: nameController,
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Full Name',
                  ),
                )),
            Container(
                margin: EdgeInsets.all(20),
                child: TextField(
                  controller: ageController,
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Age',
                  ),
                )),
            Container(
                margin: EdgeInsets.all(20),
                child: TextField(
                  controller: addressController,
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Address',
                  ),
                )),
            Container(
                margin: EdgeInsets.all(20),
                child: TextField(
                  controller: weightController,
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Weight',
                  ),
                )),
            Container(
                margin: EdgeInsets.all(20),
                child: TextField(
                  controller: heightController,
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Height',
                  ),
                )),
            Container(
                margin: EdgeInsets.all(20),
                child: TextField(
                  controller: traitController,
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Unique Trait',
                  ),
                )),
            // Container(
            //     margin: EdgeInsets.all(20),
            //     child: TextField(
            //       controller: appearanceController,
            //       decoration: InputDecoration(
            //         border: OutlineInputBorder(),
            //         labelText: 'Apperance',
            //       ),
            //     )),
            ElevatedButton(
              child: Text('Next'),
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => SecondRoute()),
                );
              },
            ),
            Container(
              margin: EdgeInsets.all(20),
              child: Text(fullName),
            )
          ]))),
    );
  }
}

class SecondRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Camera"),
        ),
        body: Center(
            child: ElevatedButton(
                onPressed: () {
                  Navigator.pop(context);
                },
                child: Text("Back"))));
  }
}

You have to separate MaterialApp. Create separate class for pages.Only then you can able to navigate from one page to another.

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
 

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.pink,
      ),
      home:FirstPage(),
    );
  }
}

class FirstPage  extends StatefulWidget{
  @override
  _FirstPageState createState() => _FirstPageState();
}

class _FirstPageState extends State<FirstPage> {
   TextEditingController nameController = TextEditingController();

  TextEditingController ageController = TextEditingController();

  TextEditingController addressController = TextEditingController();

  TextEditingController weightController = TextEditingController();

  TextEditingController heightController = TextEditingController();

  TextEditingController traitController = TextEditingController();

  TextEditingController appearanceController = TextEditingController();

  String fullName = '';

    Widget build(BuildContext context){
      return  Scaffold(
          appBar: AppBar(
            title: Text('Input Information'),
          ),
          drawer: Drawer(
            child: ListView(
              padding: EdgeInsets.zero,
              children: <Widget>[
                DrawerHeader(
                  child: Text('Drawer Header'),
                  decoration: BoxDecoration(
                    color: Colors.purple,
                  ),
                ),
                ListTile(
                  title: Text('Item 1'),
                  onTap: () {
                    Navigator.pop(context);
                  },
                ),
                ListTile(
                  title: Text('Item 2'),
                  onTap: () {
                    Navigator.pop(context);
                  },
                ),
              ],
            ),
          ),
          body: SingleChildScrollView(
            child: Center(
                child: Column(children: <Widget>[
              Container(
                  margin: EdgeInsets.all(20),
                  child: TextField(
                    controller: nameController,
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      labelText: 'Full Name',
                    ),
                  )),
              Container(
                  margin: EdgeInsets.all(20),
                  child: TextField(
                    controller: ageController,
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      labelText: 'Age',
                    ),
                  )),
              Container(
                  margin: EdgeInsets.all(20),
                  child: TextField(
                    controller: addressController,
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      labelText: 'Address',
                    ),
                  )),
              Container(
                  margin: EdgeInsets.all(20),
                  child: TextField(
                    controller: weightController,
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      labelText: 'Weight',
                    ),
                  )),
              Container(
                  margin: EdgeInsets.all(20),
                  child: TextField(
                    controller: heightController,
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      labelText: 'Height',
                    ),
                  )),
              Container(
                  margin: EdgeInsets.all(20),
                  child: TextField(
                    controller: traitController,
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      labelText: 'Unique Trait',
                    ),
                  )),
              // Container(
              //     margin: EdgeInsets.all(20),
              //     child: TextField(
              //       controller: appearanceController,
              //       decoration: InputDecoration(
              //         border: OutlineInputBorder(),
              //         labelText: 'Apperance',
              //       ),
              //     )),
              ElevatedButton(
                child: Text('Next'),
                onPressed: () {
                   Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => SecondRoute()),
                );
                },
              ),
              Container(
                margin: EdgeInsets.all(20),
                child: Text(fullName),
              )
            ])),
          ));
    }
}

class SecondRoute extends StatelessWidget {
//   static const String routes = 'second-page';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Camera"),
        ),
        body: Center(
            child: ElevatedButton(
                onPressed: () {
                  Navigator.pop(context);
                },
                child: Text("Back"))));
  }
}

One solution is to wrap your ElevatedButton in a Builder widget.

                Builder(
                  builder: (context) => ElevatedButton(
                    child: Text('Next'),
                    onPressed: () {
                      Navigator.push(
                        context,
                        MaterialPageRoute(builder: (context) => SecondRoute()),
                      );
                    },
                  ),
                ),

Sibling vs. Child

This works because your ElevatedButton is a child of MyApp widget, not of MaterialApp widget. MaterialApp provides a default Navigator to its children. But, ElevatedButton is currently a sibling of MaterialApp , not its child (context wise).

It can be difficult to see this due to the how long & nested Dart code can appear.

Context Hierarchy

Here's another way seeing the code in the question in terms of hierarchy:

main
  MyApp(context)
    MaterialApp(theme, home, body) ← everything at this level is using MyApp context

Your body: argument ↑ expanded is ↓:

main
  MyApp(context)
    MaterialApp(theme, home, body: Center(container x6, ElevatedButton(context)))

... which means ElevatedButton is getting MyApp context .

Going down another level:

main
  MyApp(context)
    MaterialApp(theme, home, body)
      Widgets on this level will use MaterialApp context

Wrapping ElevatedButton in Builder , pushes ElevatedButton down a level. That's Builder's job, to make whatever you give it, children of its context level.

So with Builder the above now becomes:

main
  MyApp(context)
    MaterialApp(theme, home, body: Center(container x6, Builder))
                                                           ElevatedButton ← uses MaterialApp context

Navigator (sneaky) Context

Navigator.push(context) is also very easy to misunderstand how it's using the supplied context . For more background on that, see this answer I wrote for a similar issue, where I explain Navigator.of in more detail.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM