Exception when trying to use navigator - android

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(),
);
}
}

Related

showing a dialog doesn't work when the widget is the direct child of MaterialApp

I'm trying to create an alert dialog in Flutter, but the dialog doesn't work when it is under MaterialApp and instead gives an error. Below is the code:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Inputs and alerts'),
),
body: ElevatedButton(
child: const Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text('This is a text'),
content: Text('this is the content'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text('No'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text('Yes'),
)
],
);
},
);
},
),
),
);
}
}
Error
But when I extract the ElevatedButton to a stand-alone widget, the alert dialog works fine. Here is the code:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Inputs and alerts'),
),
body: sn(),
),
);
}
}
class sn extends StatelessWidget {
const sn({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: ElevatedButton(
child: const Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text('This is a text'),
content: Text('this is the content'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text('No'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text('Yes'),
)
],
);
},
);
},
),
);
}
}
Output
Can anyone tell me the cause of this behaviour? Any help is greatly appreciated.
This happens because you can only call showDialog(context) passing in a BuildContext that has an MaterialApp as an ancestor widget. The context you're getting access in your build() method from your first example is a context that does not have any MaterialApp above it.
Just like you did, you can solve this by extracting your Scaffold into another widget to have access to it's BuildContext in the build method.
Another solution is to use a Builder widget. It exposes a new context to it's child that now has in it the reference to any widget above it (in this case the MaterialApp).
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(builder: (context) {
return Scaffold(
appBar: AppBar(
title: const Text('Inputs and alerts'),
),
body: ElevatedButton(
child: const Text('Show Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text('This is a text'),
content: Text('this is the content'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text('No'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text('Yes'),
)
],
);
},
);
},
),
);
}),
);
}
}

The instance member 'setState' can't be accessed in an initializer

im Very new in flutter . i dont know what to do to fix this .
im trying to Use Flutter Plugin :
flutter_numpad_widget
Here my Full code:
import 'package:flutter/material.dart';
import 'package:flutter_numpad_widget/flutter_numpad_widget.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
bool _confirmEnabled = false;
class _MyAppState extends State<MyApp> {
int maxRawLength;
final NumpadController _numpadController = NumpadController(
format: NumpadFormat.NONE,
hintText: "Ketikkan NIP",
onInputValidChange: (bool valid) => setState(() {
_confirmEnabled = valid;
}),
);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Numpad Example',
theme: ThemeData(
primarySwatch: Colors.amber,
buttonTheme: ButtonThemeData(
textTheme: ButtonTextTheme.normal,
buttonColor: Colors.blueGrey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30))))),
home: Scaffold(
appBar: AppBar(
title: Text('Numpad Example'),
),
body: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: NumpadText(
style: TextStyle(fontSize: 30),
controller: _numpadController,
),
),
Expanded(
child: Numpad(
controller: _numpadController,
buttonTextSize: 40,
),
)
],
),
),
));
}
}
im following the documentation here :
onInputValidChange
but in this line its keep getting me Error "The instance member 'setState' can't be accessed in an initializer.":
onInputValidChange: (bool valid) => setState(() {
_confirmEnabled = valid;
}),
im Already searching in few days and gets nothing.
thanks for your help priciateit
To add some explanation to your problem and I think in general is also valid:
You should init all your state properties in initState. If you have like bool flags or primitive properties that's fine but objects, in general, you should init in ```initState````. In your case:
import 'package:flutter/material.dart';
import 'package:flutter_numpad_widget/flutter_numpad_widget.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
bool _confirmEnabled = false;
class _MyAppState extends State<MyApp> {
int maxRawLength;
final NumpadController _numpadController; // this is the declaration
#override
void initState() {
super.initState();
_numpadController = NumpadController( // here is the init
format: NumpadFormat.NONE,
hintText: "Ketikkan NIP",
onInputValidChange: (bool valid) => setState(() {
_confirmEnabled = valid;
}),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Numpad Example',
theme: ThemeData(
primarySwatch: Colors.amber,
buttonTheme: ButtonThemeData(
textTheme: ButtonTextTheme.normal,
buttonColor: Colors.blueGrey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30))))),
home: Scaffold(
appBar: AppBar(
title: Text('Numpad Example'),
),
body: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: NumpadText(
style: TextStyle(fontSize: 30),
controller: _numpadController,
),
),
Expanded(
child: Numpad(
controller: _numpadController,
buttonTextSize: 40,
),
)
],
),
),
));
}
}
You should declare your state inside The state widget like this:
class _MyAppState extends State<MyApp> {
int maxRawLength;
bool _confirmEnabled = false; // here
....
onInputValidChange: (bool valid) => setState(() {
_confirmEnabled = valid;
}),
...

How to change state of one Stateful Widget from another Stateful Widget in Flutter?

In this code, I want to show indexed widgets by changing the index from the Navigation drawer i.e. The main MaterialApp shows widget according to the index(widgetIndex). The index is updated but the widget does not change until I hot reload it. So, I want it to reload the MyApp widget from the drawer widget.
main.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:indexed/page1.dart';
import 'package:indexed/page2.dart';
import 'drawer.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
//set widgetIndex(int widgetIndex) {widgetIndex = DrawerS.widgetIndex;}
int widgetIndex = SideDrawerState.widgetIndex;
#override
Widget build(BuildContext context)
{
return MaterialApp(
home: Container(
child: IndexedStack(
index: widgetIndex,
children: <Widget>[
Page1(), //A Scaffold wid.
Page2(), //A Scaffold wid.
],
),
),
);
}
}
drawer.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SideDrawer extends StatefulWidget {
#override
SideDrawerState createState() => SideDrawerState();
}
class SideDrawerState extends State<SideDrawer> {
static int widgetIndex = 0;
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
ListTile(
contentPadding: EdgeInsets.only(top: 50),
title: Text('1'),
onTap: () async {
setState(() => widgetIndex = 0);
Navigator.of(context).pop();
},
),
ListTile(
title: Text('2'),
onTap: (){
setState(() => widgetIndex = 1);
Navigator.of(context).pop();
},
),
],
),
);
}
}
You can create a function field in your SideDrawer that takes an index as a parameter.
Call the function passing the appropriate parameter in the onTap of each ListTile.
In your MyApp create a variable with initial value of 0 then when setting the SideDrawer add the onTap attribute then change the value of the in the setState
Like this
class MyApp2 extends StatefulWidget {
#override
MyApp2State createState() => MyApp2State();
}
class MyApp2State extends State<MyApp2> {
var widgetIndex = 0;
#override
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: SafeArea(
child: Container(
child: IndexedStack(
index: widgetIndex,
children: <Widget>[
Text("djdhjhd"),
Text("nonono")
],
),
),
),
drawer: SideDrawer(
onTap: (index){
setState(() {
widgetIndex = index;
});
},
),
);
}
}
class SideDrawer extends StatefulWidget {
final Function(int index) onTap;
SideDrawer({this.onTap});
#override
SideDrawerState createState() => SideDrawerState();
}
class SideDrawerState extends State<SideDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
ListTile(
contentPadding: EdgeInsets.only(top: 50),
title: Text('1'),
onTap: () async {
widget.onTap(0);
Navigator.of(context).pop();
},
),
ListTile(
title: Text('2'),
onTap: (){
widget.onTap(1);
Navigator.of(context).pop();
},
),
],
),
);
}
}
The output:
I hope this helps you.

Creating flutter expandable with toggle button

I got some difficulties implementing UI design in flutter. I wanna make an expanded widget like this, can I have a clue?
collapsed:
expanded
I have tried to use Expandable but I just can't get it looks like my design. Thanks
You can use AnimatedContainer.
For example :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool expanded = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Example')),
body: Column(
children: [
Container(color: Colors.green, height: 100),
AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: expanded ? 120 : 0,
child: Container(height: 120, color: Colors.red),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
child:
Icon(expanded ? Icons.arrow_upward : Icons.arrow_downward),
onPressed: () => setState(() {
expanded = !expanded;
}),
),
],
),
],
),
);
}
}

how to fix flutter exception : Navigator operation requested with a context that does not include a Navigator

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()),
);
},
),
);
}
}

Categories

Resources