Navigate to Additional Page Seconds after First Loads - flutter

Say my app starts on PageA, I'm trying to navigate to PageB 2 seconds after it loads.
Here is what I've tried...
In PageA:
Future _sleepTwo() {
return new Future.delayed(const Duration(seconds: 2), () => "sleeping...");
}
#override
void initState() {
this._sleepTwo().then((res) {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => PageB(),
));
});
}
But this gives me the following error:
E/flutter (22949): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
E/flutter (22949): 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.
I've looked everywhere but got nowhere.
I even tried wrapping everything in initState() with a Future(() => {code here});. But it didn't work.

You won't have a context if the page hasn't initialized. Insert the following code into your Widget build(BuildContext context) method.
_sleepTwo().then((res) {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => PageB(),
));
});
Don't use the await keyword if you want the PageA to still draw itself, and then after two seconds switch to PageB

Related

ChangeNotifier inaccessible in grandchildren widget of where it was provided

I am trying to use flutter provider in order to carry my state down a widget sub-tree/route, and while it works for the direct child of the widget that provided the change notifier class, it does not for the next one in line.
As far as I understand, the change notifier class should be passed down. To be more specific, I am trying to access it through context.read() in a function being called in its initState function.
Am I doing something wrong?
The code below illustrates my code.
Where it class notifier is provided:
onTap: () {
// Select body area
context.read<Patient>().selectBodyArea(areas[index]);
// Open complaint list
FlowRepresentation flow = context.read<Patient>().getFlow();
Navigator.push(
context,
MaterialPageRoute(builder: (context) =>
ChangeNotifierProvider.value(
value: flow,
child: const ChiefComplaintList()
)
)
);
}
Navigation to the problem widget in ChiefComplaintList:
onTap: () {
// Select complaint
context.read<FlowRepresentation>().selectComplaint(ccs[index]);
// Show factors
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const AttenuationFactors())
);
}
Where I'm having trouble accessing the change notifier class:
void getData() async {
_nrFactors = await context.read<FlowRepresentation>().getAttenuationFactors();
setState(() {}); // rebuild widget with data
}
#override
void initState() {
super.initState();
print("Initiated Attenuation Factors Lists State");
getData();
}

Flutter how to open page from push notification, context issue

void selectNotification(String? payload) async {
print('Selected notification');
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SearchScreen(),
),
);
}
I am using this method to open a screen when the notification is tapped, I get the print message fine but then the Navigator message shows:
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.
Im just trying to have it so if the notificaiton is tapped from foreground, background where ever the app then just pops open that screen but I cant get it to work
void selectNotification(String? payload, BuildContext context) async {
print('Selected notification');
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SearchScreen(),
),
);
}
Use getX package and use navigation routing:
something like this:
Get.put(()=> **your page**
getX package

flutter Navigator in initState, not working

i have code like this from the internet, and my is not working:
class _StartingAnimationState extends State<StartingAnimation>{
#override
void initState() {
Future.delayed(Duration(seconds: 4),(){
Navigator.push(context, MaterialPageRoute(builder: (context) {
return mainWindow();
}));
});
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SizedBox(height: 300,width: 300, child: Lottie.asset("assets/lottie/login.json")),
);
}
}
I got error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
and
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.
I want my program to show animation for some time, and then navigate to other screen
You can't push a new route in initState. How ever you can register a post frame callback that can run a function.
In you build method, before the return statement:
WidgetsBinding.instance.addPostFrameCallback((_){
Future.delayed(Duration(seconds: 4),(){
Navigator.push(context, MaterialPageRoute(builder: (context) {
return mainWindow();
}));
});
});
return MaterialApp(
home: SizedBox(height: 300,width: 300, child: Lottie.asset("assets/lottie/login.json")),
//home: SizedBox(height: 300,width: 300, child: Lottie.asset("assets/lottie/login.json")),
);
i find answer for eanyone who will find this question
answer is:
i didnt put MaterialApp in my main:
runApp(MaterialApp(home: StartingAnimation()));
and also i saw mistake in my initState:
#override
void initState() {
super.initState();
Future.delayed(Duration(seconds: 4),(){
Navigator.push(context, MaterialPageRoute(builder: (context) {
return mainWindow();
}));
});
}
Why it's not working?
The MaterialApp configures the top-level Navigator to search for navigation routes in order:
For the / route, the home property, if non-null, is used.
Otherwise, the routes table is used, if it has an entry for the route.
Otherwise, onGenerateRoute is called, if provided. It should return a
non-null value for any valid route not handled by home and routes.
Finally if all else fails onUnknownRoute is called.
That's why error comes when the above approach did not follow Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
Solution!!!
Wrap StartingAnimation with MaterialApp
runApp(MaterialApp(home: StartingAnimation()));
Note: This only happens when navigation is done on the route widget, if done on other widgets/screens, it will not occur as MaterialApp already initialized as everyone added at the top.

Show Dialog In InitState Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe

At first time screen appears, i want check if user GPS is enable and Location Permission is granted. Then if one of them is not fulfilled , i show dialog to open app setting.
Source Code
_initPermission(BuildContext context) async {
final geolocationStatus = await commonF.getGeolocationPermission();
final gpsStatus = await commonF.getGPSService();
if (geolocationStatus != GeolocationStatus.granted) {
showDialog(
context: context,
builder: (ctx) {
return commonF.showPermissionLocation(ctx);
},
);
} else if (!gpsStatus) {
showDialog(
context: context,
builder: (ctx) {
return commonF.showPermissionGPS(ctx);
},
);
}
}
Then i called this function in initState like this :
InitState
void initState() {
super.initState();
Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission(context));
}
The problem is , every first time the screen appears it will give me error like this :
Error
[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
What i have done :
Change InitState like this
//1
WidgetsBinding.instance.addPostFrameCallback((_) {
_initPermission(context);
});
//2
SchedulerBinding.instance.addPostFrameCallback((_) => _initPermission(context));
//3
Timer.run(() {
_initPermission(context);
})
Adding Global Key For Scaffold
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
Scaffold(
key: _scaffoldKey,
Searching similiar problem with me
Show Dialog In Initstate
Looking up a deactivated widget's ancestor is unsafe
Load Data In Initstate
The results that I have done is nothing , the error still appear in first time screen appear.
But strangely, this only happens when first time screen appear . When i do Hot Restart the error message is gone.
[Failed if screen first time appear]
[Hot restart , error gone]
I have no way to test it (I dont have the GPS package) but try changing
Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission(context));
to
Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission()); //this inside the initstate
_initPermission() async{
final geolocationStatus = await commonF.getGeolocationPermission();
final gpsStatus = await commonF.getGPSService();
if (geolocationStatus != GeolocationStatus.granted) {
await showDialog(
context: context,
builder: (ctx) => commonF.showPermissionLocation
},
);
} else if (!gpsStatus) {
await showDialog(
context: context,
builder: (ctx) => commonF.showPermissionGPS
},
);
}
} // the stateful widget can use the context in all its methods without passing it as a parameter
The error dissapears in hot restart because it just refresh the state of the widget, but it's already created (If you do hot restart and print something inside the initState, for example print('This is init');, you wont see it either because the refresh doesn't dispose and init the widget, so it won't run that piece of code again)
EDIT
Based on your gist I just made a minimal reproducible example and run with no problem in DartPad, later I will try it on VS but for now can you check if there is anything different
enum GeolocationStatus{granted, denied} //this is just for example
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
showPermissionGPS() {
return AlertDialog(
title: Text('GPSStatus'),
);
}
_showPermissionLocation() {
return AlertDialog(
title: Text('Permission Localization'),
);
}
#override
initState(){
super.initState();
Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission());
}
_initPermission() async{
final geolocationStatus = await Future<GeolocationStatus>.value(GeolocationStatus.granted); //mocked future with a response to test
final gpsStatus = await Future<bool>.value(false); //mocked future with a response to test
if (geolocationStatus != GeolocationStatus.granted) {
await showDialog(
context: context,
builder: (ctx) => _showPermissionLocation() //this mock commonF.showPermissionLocation and returns an AlertDialog
);
} else if (!gpsStatus) {
await showDialog(
context: context,
builder: (ctx) => _showPermissionGPS() //this mock commonF.showPermissionGPS and returns an AlertDialog
);
}
}
#override
Widget build(BuildContext context) {
return Text('My text');
}
}

How to get a context for Navigator in Widget initState()?

I want my app to work offline without a user set, and asking for a login when connectivity is back
en excerpt of the code I'm trying:
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
Connectivity().onConnectivityChanged.listen((ConnectivityResult result) =>
checkConnectivity().then((isOnline) {
if (isOnline && MyApp.store.state.user == null)
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => LoginPage()),
);
}));
}
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
...
but all I can get is this error:
Unhandled Exception: 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.
I tried to wrap my Navigator call inside a Future.delayed as described here but I got the same error