Flutter setEnabledSystemUIOverlays hide top statusbar - dart

I encountered a problem when I set the SystemUiOverlay.bottom on my appbarwidget using SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]) and noticed that status bar is hidden but once I pull down upper side of the screen it shows and doesn't disappear again. So I came up with the idea to add a gesture detector for the whole widget app to hide it all the time when you press anywhere on the screen. And I am wondering if this is the best solution and there will not be any issues with the performance or whatever. Any thoughts?
void main() => runApp(PlanetsApp());
class PlanetsApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: () => SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]),
child: new MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Planets App',
color: Colors.purple,
home: HomeScreen(),
),
);
}
}

After switching to Flutter I also noticed this behavior :(
I dont want to use GestureDetector, and I am not sure where to place SystemChrome.setEnabledSystemUIOverlays so it hides the bar properly...
Instead, I did this: in the Android styles.xml where the App theme is I've added:
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
This makes the sys-bar to always disappear when the app gets clicked

change your code to this.
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);

For the issue (https://github.com/flutter/flutter/issues/14432) mentioned in comment, I've found a temporary solution. When you hide status bar or bottom bar, Appbar's height remains same and it takes too much space, especially when you are using landscape mode. To fix this, set "primary" property of Scaffold and Appbar false.
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
SystemChrome.setEnabledSystemUIOverlays([]);
super.initState();
}
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
primary: false,
appBar: AppBar(
primary: false,
backgroundColor: Colors.blue,
),
body: Center(child: Text("It works!")),
),
);
}
}
Hope it helps!

There is not fix for this as of right now. When status bar is hidden, app bar's height remains the same.
See the github issue: https://github.com/flutter/flutter/issues/14432

Related

Why is there overlap between a Flutter CupertinoApp's header and slivers underneath unless I wrap it in a Material widget?

This seems like a bug, but I wanted to solicit feedback first. In my simple demo app below, you can see where the SliverChildBuilderDelegate is generating Text widgets as the SliverList. When you scroll up the text widgets overlap with the header. If you wrap the Text widget in a Material widget then that solves the problem (perhaps it's because of Material's clipping capability?). Mixing Material and Cupertino widgets isn't the best, however, particularly if you want to use a CupertinoTheme.
Any suggestions about what's going on and what to do about it is appreciated.
thanks
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return CupertinoApp(
title: 'Cupertino Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: SafeArea(
child: CustomScrollView(
shrinkWrap: true,
slivers: [
CupertinoSliverNavigationBar(
largeTitle: Text('Cupertino Demo'),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(_, index) => Material(child: Text('This is list item number $index')),
),
)
],
),
),
);
}
}
Because of the shrinkWrap:true, you can read more here:
https://github.com/flutter/flutter/issues/28197
I don't see why would you need that, so simply just remove and it will work.

Default back button not showing after pushing new screen

I had pushed a new Screen from my main screen and it had navigated smoothly and also showed the back button however now that I run the button, the default button is not showing in my code.
The only change that I made was that I changed the route in my main file from taskScreen() to task().
But this was essential as i wanted to make some more routes from my second screen and so it had to return a Material App.
How can i get the default back button back?
My code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: DefaultTabController(length: 2,child: MyHomePage(title: '')),
routes: <String, WidgetBuilder>{
"/TaskScreen": (BuildContext context) => new task(), //CHANGED HERE
},
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
..
),
body: ...
}
}
My second screen
class task extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Task',
home: new taskScreen(),
routes: <String, WidgetBuilder>{
"/Completed": (BuildContext context) => new Completed()
}
);
}
}
class taskScreen extends StatefulWidget{
#override
taskState createState() => new taskState();
}
class taskState extends State<taskScreen> {
#override
Widget build(BuildContext context) {
Column taskScreen = Column (...)
return Scaffold(
appBar: AppBar(
title: Text('Task Screen')),
body: taskScreen,
);
}
}
Class name must to start with uppercase character. You have wrong structure, MaterialApp must to be only one time.
https://dart.dev/guides/language/language-tour
For me it happened when I added a draw to all my various AppBars ... quick googling provided a solution which worked for me:
I added to the AppBar the following which let flutter take a conscious decision whether there is or is not what to go back to ...
automaticallyImplyLeading: true,
Then I added defined how the "leading" should look like (also to the appbar):
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context, false),
),
Making a long story short: Adding the following to the respective AppBar did the work:
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context, false),
),
Remove the second routes MaterialApp and replace it with an AppBar

Flutter Globals losing their value

Okay, I am sure this is probably an easy to answer question, but after much searching I can't put my finger on the solution.
How does one in Flutter/Dart create a variable in app XYZ that maintains its' value during the time a user moves away from the app, uses another app, allows the phone to go to sleep, etc., then opens the XYZ app again.
I've created a tiny little app that demonstrates the issue as shown below.
The static variable Globals.UID can be incremented upwards, but if the app is moved away from (what term describes using another app correctly?) then as noted the phone goes to sleep, when the user comes back to the app the Globals.UID variable is reset back to -1.
Sometimes the reset is not immediate and I have to let the IOS phone sleep for perhaps 5 minutes to recreate the behavior.
Basically I need Globals.UID to retain its' value until the app is actually exited.
Any insight would truly be appreciated.
import 'package:flutter/material.dart';
import 'package:test_flutter/Globals.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
Globals.UID ++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
Text ( "Global variable is:")
, Text ( Globals.UID.toString() )
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
And in a different file called Globals.dart
class Globals {
static int UID = -1;
}
Thank you!
Ultimately, the solution appears to be solved mostly by using the shared_preferences library. That solution brings with it a good many documented problems, but to maintain data while the app is placed in the background, or even killed by perhaps the user, shared_preferences appears to be the way to go.
Actually this happens to when you don't import with reference. This is a known issues which is already fixed, may be not landed yet. You can check the issue here.
Please try import package_name/globals.dart instead of just import globals.dart if you are doing so.
Hope that helps!

Flutter iOS Google maps: weird appear animation

I'm having an issue with Flutter Google maps official plugin on iOS both in debug and release builds which occurs when you open an app from a terminated state. No issue on Android
There's a weird appear animation playing when I have Google Map in my widget, especially it's annoying when there's a centered floating action button as well, it has some slide in animation too
Check this video https://www.youtube.com/watch?v=94ee6cePbWw&feature=youtu.be
If you play it frame by frame, you'll see that app bar is colored correctly, floating action button is drawn, but then everything is flashed white and floating action button suddenly plays a slide in appearing animation, when it was already displayed. It all looks very glitchy
If I remove Google map from my widget, everything works fine: there's no FAB slide in animation and app bar is not flashed white, after they were drawn.
Running on Flutter v1.1.4. I want to get rid of this appear animation, thanks for the support
Here's my code
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: '',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: ''),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('')),
body: GoogleMap(
onMapCreated: (controller) {},
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
You should realize that this is a developer preview. Until the version number hits 1.0, all bets are off about how well it performs, and even if it's suitable.

Flutter TextFormField reloads current screen when focused

I have a TextFormField that reloads the current screen when I tap on it to enter text. When I tap on the formfield the software keyboard is displayed briefly before the entire screen reloads and renders all the widgets again. I am running the app on an Android device.
Container(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Your input cannot be empty';
}
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
onPressed: () {
if (_formKey.currentState.validate()) {
print('validated');
}
},
child: Text('Save'),
),
),
],
),
),
margin: EdgeInsets.only(top:8.0),
),
The problem is that the controller of the TextFormField is rebuild when you click on the field, and that's the reason of your issue.
So to solve that, did you try to create a Statefull widget and then creating a TextEditingController in the State of this widget and passing it as an argument to the TextFormField ?
I had the same Problem. this was my code
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Model model = Model();
#override
Widget build(BuildContext context) {
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
var mediaWidth = MediaQuery.of(context).size.width / 2.0;
return Scaffold(
...
and I solved this problem by declaring the _formKey outside of build method. and this worked for me.
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Model model = Model();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
var mediaWidth = MediaQuery.of(context).size.width / 2.0;
return Scaffold(
...
hope it will help you
Yes, that happens because when the keyboard appears, the flutter scaffold gets resize to the current available screen size. So, we can easily handle this by preventing the scaffold size change. I suggest to set scaffold resizeToAvoidBottomInset property false. If it's true the body and the scaffolds floating widgets should size themselves to avoid the onscreen keyboard whose height is defined by the ambient MediaQuery's, MediaQueryData,viewInsets bottom property.
Solution:
resizeToAvoidBottomInset: false,
Complete example:
#override
Widget build(BuildContext context) {
setDisplayData();
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: getAppBar(),
body: OrientationBuilder(
builder: (context, orientation) {
return orientation == Orientation.portrait
? _buildVerticalLayout()
: _buildHorizontalLayout();
},
),
);
Check if you are using MediaQueries wrongly in your project, I had similar issue and it stopped when I changed the MediaQuery
in my case:
Size _size = MediaQuery.of(context).size;
removing this piece of code fixed my app.
When TextFormField focused the size of screen will changed because of the appearance of keyboard, that cause rebuild of state, you cant prevent re-build of state.
Instead of trying prevent re-build state, you need to solve problems which happen when state do re-build, one of common problem is declaration and initialization variables inside build(BuildContext context){ ... }' function.
The main problem, when you need to get some data related of context (like size of screen), in this case I prefer to pass this value from parent Widget...
For example this code will cause problem when re-build state:
#override
Widget build(BuildContext context) {
double? _screenHeight = MediaQuery.of(context).size.height;
return Container();
}
To solve problem get _screenHeight from parent, to know how to do that look at https://stackoverflow.com/a/50289032/2877427

Resources