I'm not able to navigate screen showing error 'Navigator operation requested with a context that does not include a Navigator, I have tried many solutions where navigator is used in Builder with stateless widgets but here navigation is done automatically after a few seconds in override method in intiSate. my aim is to navigate the screen after a few seconds.
class Splash extends StatelessWidget {
#override
Widget build(BuildContext context) {
return testWidget;
}
}
Widget testWidget = new MediaQuery(
data: new MediaQueryData(),
child: new MaterialApp( title: 'xxxxxxxxxxxxx',
home: SplashScreen(),
debugShowCheckedModeBanner: false,
routes: <String, WidgetBuilder>{
'/login': (BuildContext context) => new Login(),
},
)
);
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
Future initState () {
super.initState();
new Future.delayed(
const Duration(seconds: 2), () => Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => Login()),
));
}
#override
Widget build(BuildContext context) {
return(Scaffold(
body: Container(
height: double.infinity,
width: double.infinity,
child: Image.asset('assets/images/crop.jpg',fit:BoxFit.fill),
),
));
//build
}
}
Showing Error
Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
Code Corrected:
MaterialApp Should always be the Root Widget of all Widgets.
That Way Navigator is always Available.
void main() => runApp(Splash());
class Splash extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: testWidget,
debugShowCheckedModeBanner: false,
);
}
}
Widget testWidget =
new MediaQuery(data: new MediaQueryData(), child: new SplashScreen());
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
super.initState();
Future.delayed(
const Duration(seconds: 2),
() => Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => Login()),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Spalsh'),),
body: Container(
height: double.infinity,
width: double.infinity,
// child: Image.asset('assets/images/crop.jpg', fit: BoxFit.fill),
),
);
//build
}
}
class Login extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login Page'),
),
body: Container(),
);
}
}
Related
I am getting an exception: FlutterError (Navigator operation requested with a context that does not include a Navigator. The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.)
This is the important code of the first page (Skipped some code with ... that wasn't relevant):
import 'package:google_fonts/google_fonts.dart';
import 'register.dart';
void main() async {
...
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
...
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
textTheme: GoogleFonts.interTextTheme(
Theme.of(context).textTheme,
)),
home: Scaffold(
body: Container(
width: double.infinity,
...
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondRoute()));
},
child: Text(
"Forgot Password?",
style: GoogleFonts.inter(
fontWeight: FontWeight.w600,
),
),
),
),
...
),
));
}
}
This is the second page:
import 'package:flutter/material.dart';
class SecondRoute extends Navigator {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
);
}
}
There are no syntax errors only exceptions thrown when the code is run. I have tried already looking for the solution but the other way of putting the material app in the runApp() method, to my understanding doesn't work for the way I use the Text Theme and use context.
Let me know if I need to give more code or context.
Any help would be greatly appreciated!
Try changing:
class SecondRoute extends Navigator {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
);
}
}
to:
class SecondRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
);
}
}
Edit, also move the scaffold from _MyAppState into it's own widget.
class FirstRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox(
width: double.infinity,
child: Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {
print('hello');
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
child: Text(
"Forgot Password?",
style: GoogleFonts.inter(
fontWeight: FontWeight.w600,
),
),
),
),
),
);
}
}
And then use in _MyAppState like so:
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
textTheme: GoogleFonts.interTextTheme(
Theme.of(context).textTheme,
)),
home: FirstRoute(),
);
}
}
I want to pass MaterialPageRoute as a parameter into another page. Like if want to pass onPressed((){}) to other page we declared it as
FirstPage({
this.onPressed,
});
final GestureTapCallback onPressed;
How could I pass MaterialPageRoute(builder: (context) => SecondPage()) to other page as a parameter?
Here's one way to do that:
class MyApp extends StatelessWidget {
const MyApp({Key? key}): super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: FirstPage(
materialPageRoute: MaterialPageRoute(builder: (context) => const SecondPage()),
)
);
}
}
class FirstPage extends StatelessWidget {
const FirstPage({
Key? key,
required this.materialPageRoute,
}): super(key: key);
final MaterialPageRoute materialPageRoute;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
onPressed: () => Navigator.of(context).push(materialPageRoute),
child: const Text('Navigate to SecondPage'),
),
)
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({Key? key}): super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const Center(
child: Text('Second Page'),
),
);
}
}
I'm trying to find a way to add an AppBar only once without having to duplicate the AppBar code on different routes. I have tried different approaches but I still cant get the results that I want.
This is the main.dart file.
import 'package:flutter/material.dart';
import 'package:com.example.simple_app/pages/page_one.dart';
import 'package:com.example.simple_app/pages/page_one.dart';
void main() => runApp(SimpleApp());
final routes = {
'/': (BuildContext context) => new PageOne(),
'/pageone': (BuildContext context) => new PageOne(),
'/pagetwo': (BuildContext context) => new PageTwo(),
};
class SimpleApp extends StatefulWidget {
#override
_SimpleAppState createState() => _SimpleAppState();
}
class _SimpleApp extends State<SimpleApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Simple App',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blueGrey,
),
initialRoute: '/',
routes: routes,
);
}
}
Below is PageOne.dart file where I've hardcoded AppBar code.
import 'package:flutter/material.dart';
class PageOne extends StatefulWidget {
PageOne({Key key}) : super(key: key);
#override
_PageOneState createState() => _PageOneState();
}
class _PageOneState extends State<PageOne> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Simple AppBar'),
),
);
}
}
Below is PageTwo.dart file where I've also put AppBar by writing the whole code, I'm duplicating AppBar code which is not cool.
import 'package:flutter/material.dart';
class PageOne extends StatefulWidget {
PageOne({Key key}) : super(key: key);
#override
_PageTwoState createState() => _PageOneState();
}
class _PageTwoState extends State<PageOne> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Simple AppBar'),
),
);
}
}
I'm new to flutter but I hope you understand what I'm saying.
What I want is to be able to use AppBar in different routes without duplicating the code. For example when we go to web development, A website built in php you can simply include views. I want something similar here or better, Thank you.
You can create a separate App bar Widget for achieving this Like :
Create an appbar.dart file as :
import 'package:flutter/material.dart';
Widget appbar(BuildContext context, String title, dynamic otherData) {
return AppBar(
title: Text(title),
//Other data you want to show
);
}
And import the appear. dart file wherever you want to display an App bar.
Screen1:
import 'appbar.dart';
import 'package:flutter/material.dart';
class Page1 extends StatefulWidget {
#override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appbar(context, 'Chat App', {'icons' : Icons.menu}),
);
}
}
Screen2:
import 'appbar.dart';
import 'package:flutter/material.dart';
class Page12 extends StatefulWidget {
#override
_Page12State createState() => _Page12State();
}
class _Page12State extends State<Page12> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appbar(context, 'Chat App', {'icons' : Icons.menu}),
);
}
}
There are a lot more ways to achieve this. This is the simple one I tried.
Use builder property in MaterialApp to build common container for every page
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: Theme.of(context).copyWith(highlightColor: Colors.amber),
//TODO: Use `builder` to add top most container for all page
builder: (context, child) {
return Scaffold(
appBar: AppBar(
title: Text("Simple AppBar"),
),
body: child, //this child is dynamically replaced with corresponding page when we navigate
);
},
home: FirstPage(),
debugShowCheckedModeBanner: false,
);
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("This is First Page"),
RaisedButton(
child: Text("Goto Second Page"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
),
);
},
),
],
);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("This is First Page"),
RaisedButton(
child: Text("Go Back"),
onPressed: () {
Navigator.pop(context);
},
),
],
);
}
}
First, create a file for example appBar.dart
then place your personal appBar there like this:
import 'package:flutter/material.dart';
final appBar = AppBar(
backgroundColor: Colors.orange,
elevation: 5.0,
title: Center(
child: SizedBox(
height: 40.0,
child:Image.asset("assets/images/myLogo.png"),
),
),
);
now import and use the appBar anywhere you want.
import 'package:myApp/pages/appBar.dart';
return Scaffold(
appBar: appBar,
body:......
I am working on this app, where you can navigate to a screen with a stateful widget that has a bunch complex functions that run in initState().
Due to these functions, navigating to this screen takes close to two seconds after the Navigation function is triggered i.e It is very slow
My Code looks like this
#override
void initState(){
someComplexHeavyFunctions();
super.initState();
}
Is there any way to make sure the navigation has completed (fast and smmothly) before running the function in initState() and also, maybe showing a loader while the functions are still processing after the screen has been navigated to?
like this:
You can use the compute function to do the calculation in a different isolate which runs on a different thread.
You can call the initializing function and while awaiting for it, display the dialog.
This is a complete example:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Test"),
),
body: new Center(
child: FloatingActionButton(
child: Text("Go"),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (_) => OtherPage()));
},
),
),
);
}
}
class OtherPage extends StatefulWidget {
#override
_OtherPageState createState() => _OtherPageState();
}
class _OtherPageState extends State<OtherPage> {
bool initialized = false;
#override
void initState() {
super.initState();
initialize();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await showDialog<String>(
context: context,
builder: (BuildContext context) => new AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
CircularProgressIndicator(),
SizedBox(height: 40.0,),
Text("Performing task"),
],
),
),
);
});
}
Future<void> initialize() async {
initialized = await Future.delayed(Duration(seconds: 5), () => true);
Navigator.of(context).pop();
setState(() {});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
body: new Center(
child: initialized ? Text("Initialized") : Container(),
),
);
}
}
I am trying to create a drawer navigation using flutter framework,
but i am getting the following exception every time I run it
Another exception was thrown: Navigator operation requested with a
context that does not include a Navigator.
so what is the solution, any help ?
I used Navigator class as the following
void main() {
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return new AppStates();
}
}
class AppStates extends State<MyApp> {
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: new Scaffold(
appBar: AppBar(
title: Text("Application App Bar"),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text("Next Page"),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => NextPage()));
},
)
],
),
),
),
);
}
}
and the code of the NextPage class is
class NextPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text("Next Page App Bar"),
),
),
);
}
}
It looks like you don't have a Navigator setup for current context. Instead of using StatefulWidget you should try MaterialApp as your root App. MaterialApp manages a Navigator for you. Here is an example of how to setup an App in your main.dart
void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
home: MyApp(),
));
}
This is because the context that you're using is from the app level before a Navigator has actually been created. This is a common problem when creating "simple" single file apps in Flutter.
There are a number of possible solutions. One is to extract your Drawer into it's own class (extend Stateless/StatefulWidget accordingly), then in it's build override, the parent Scaffold will have already been created containing a Navigator for you to use.
class MyDrawer extend StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text("Next Page"),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => NextPage()));
},
)
],
),
);
}
The other, if you want to keep this Drawer in the same file, is to use a Builder instead, which has the same effect:
drawer: Builder(builder: (context) =>
Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text("Next Page"),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => NextPage()));
},
)
],
),
),
),
you need to create a new Widget as home in MaterialApp like this:-
(This worked for me)
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen());
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Title"),
),
body: Center(child: Text("Click Me")),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: Colors.orange,
onPressed: () {
print("Clicked");
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddTaskScreen()),
);
},
),
);
}
}