void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
runApp(const MyApp());
}
I want to show the ui part like this. I wrote this code in main.dart but after showing the ui it instantly closes and shows up in full screen again. How can fix this problem?
Wrap the Scaffold in a SafeArea widget
Related
I have read all the questions related to this issue, but neither of them is similar to mine.
I have two pages: homepage and settings page. In the homepage, I listen to changes of provider with Consumer. In the settings page, I don't listen to changes:
class _SettingsState extends State<Settings> {
StatesProvider states;
#override
void initState() {
states = Provider.of<StatesProvider>(context, listen: false);
super.initState();
}
#override
Widget build(BuildContext context) {
return myUi();
}
#override
void deactivate() {
states.changeSettings(settings); //just a dummy function, doesn't do anything
states.finishSetting();
super.deactivate();
}
}
I have cut out unnecessary codes. What I am trying to do in code above is changing some app settings and applying them when I leave that settings page.
finishSetting() method:
finishSetting() {
notifyListeners();
}
Error:
The following assertion was thrown while dispatching notifications for StatesProvider:
setState() or markNeedsBuild() called during build.
I know that notifyListeners() calls build() method of Widgets listening to it. But when I leave the settings page, I don't see any widget's build() method called. What should I do?
Generally, is there a way to call notifyListeners() when I leave page?
This could be that you are overwriting the wrong function:
deactivate is called when the widget gets temporarily deactivated
Try using "dispose, which is called after deactivate if the widget is removed from the tree permanently"
In general I would advise you to have a look at navigation, maybe a simple "onPopPage" at the place where you are routing to your page could be what you are looking for.
I am new in Flutter. I am working on one of my demo Flutter app. I have created 3 screens (Login, Signup and Home) in my app. I am just navigating to the Home screen from the login screen. Now I want to check - Is my app is alive or closed? - by clearing the app from the recent apps in Android and IOS. I have checked AppLifecycleState.detached and also checked override method dispose() but these are not calling while user killed the app. Please help me how I come to know that my app got killed. Which method I need to use.
I have used AppLifecycleState.paused for other process. So I want any other way to handle it.
In native Android we can check this with the help of onDestroy() method and in iOS native app we can check it with the help of applicationWillTerminate() .
Which method I need to use for Flutter?
I found one solution to detect if the app destroyed. In flutter we have one method name - dispose() In my case the dispose() method was not getting called on app destroy. So I just updated my dispose() method and added - #mustCallSuper #protected See the below code.
#mustCallSuper
#protected
void dispose() {
// TODO: implement dispose
WidgetsBinding.instance.removeObserver(this);
print('dispose called.............');
super.dispose();
}
In my widget witch is a StatefulWidget, my logic check a token and in error case, I navigate to my home page.
I'm waiting the widget finish to build by using this method:
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.pushNamed(context, '/');
});
But the problem is that even if I'm not focus on this widget anymore, he will still run in background and make a redirection in loop.
In my logic, I use setState once if my accesToken is expired. After that the widget rebuild and I check with the new token send my server, and if he is empty I redirect my user to the home page. I think the problem come from the setState.
So, is there a way to kill or dispose this widget after leaving ? Or maybe an other way to navigate ?
So I'm gonna answer my own question, after several tests I found the solution.
I can break the loop by using Navigator.popAndPushNamed(context, '/')); instead of pushNamed, it will pop the route off the navigator and so the widget will stop running on background when the parent is rebuild.
I'd like to persist the scroll location of a ListView so it is restored between app restarts.
So I guess it should be saved on disk using something like shared_preferences (in NSUserDefaults on iOS and SharedPreferences on Android)
Is there a builtin way (or plugin) to do that?
If I have to do it manually, when should I save the scroll position? (In a native Android app I would do it in the onPause Activity life-cycle method.)
I searched a lot, and I can't seem to find any post or sample code that shows how to save and restore the scroll position of a ListView.
If I have to do it manually, when should I save the scroll position? (In a native Android app I would do it in the onPause Activity life-cycle method.)
You can use mixin WidgetsBindingObserver to detect when your app goes to background and when it comes to foreground by listening AppLifecycleState
The observable lifecycle events are:
paused — The application is not currently visible to the user, not responding to user input, and running in the background. It is like onPause() in Android
inactive — The application is in an inactive state and is not receiving user input. (only IOS)
resumed — The application is visible and responding to user input. It is like onPostResume() in Android
suspending — The application will be suspended momentarily. (only Android)
In example I save date instead of scroll position
class _TestPageState extends State<TestPage> with WidgetsBindingObserver {
SharedPreferences prefs;
#override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
print('state = $state'); // resumed, paused, inactive, suspending
if (state == AppLifecycleState.paused) {
prefs.setString('date', DateTime.now().toIso8601String());
}
}
_TestPageState() {
initPrefs();
}
void initPrefs() async {
prefs = await SharedPreferences.getInstance();
print(prefs.getString('date') ?? 'no date');
}
...
We now have out of the box support for state restoration in Flutter.
Check out restorationId property inside ScrollView widget.
Check out this link to understand how to implement restoration in Flutter.
https://dev.to/pedromassango/what-is-state-restoration-and-how-to-use-it-in-flutter-5blm
As you said in your question - usage of https://pub.dev/packages/shared_preferences is the best option since it utilized the native way of handling such stuff - SharedPreferences for Android and NSUserDefaults for iOs. The new way to do in Android it PersistentBundle which can be also used in flutter, but there is no analog for iOs. Also you may use all kinds of databases and file storages but it will be overkill in this case.
Storing scroll state always was a manual task on mobile - there is no shortcuts for that out of the box - so only handmade stuff or libraries.
You can store the whole state of your stateful widget there and then restore it as a whole.
Is there a way to broadcast data from one widget to other widgets? Similar to a BroadcastReceiver on Android or NSNotificationCenter on iOS.
Specifically, I'm trying to detect when a Navigator pops or pushes a new view. I added navigatorObservers to MaterialApp. And when a widget comes back to the foreground, I want to be able to notify it by broadcasting changes from didPush and didPop with the actual route that's in the current foreground
Navigator.push returns a Future that will complete when Navigator.pop is called (and this can optionally be used to pass data back to the widget that called push). So for example suppose your login button has this onPressed handler:
onPressed: () async {
bool isLoggedIn = await Navigator.pushNamed(context, '/login');
if (isLoggedIn) {
// do something
}
}
When your login page calls Navigator.pop(true), the Future will complete with a value of true which will be assigned to the isLoggedIn variable. (You'll get null if the user uses the back button to return to the previous screen.)
This is how showDialog works as well.