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.
Is there a way to use setState with StatelessWidget?
I know that I could be used with StatefulWidget and using a State, but I don't know if there's a way to use it with StatelessWidget.
I think that's a direct question and it doesn't need code to be shown.
If you could help me, I will appreciate it.
here is an example of code that makes it possible for a StatelessWidget to update itself, its from an article of Didier Boelens.
https://www.didierboelens.com/2019/09/flutter-internals/
The following useless code makes possible for a StatelessWidget to
update itself (as if it was a StatefulWidget but without using any
setState()), by using the BuildContext …
void main(){
runApp(MaterialApp(home: TestPage(),));
}
class TestPage extends StatelessWidget {
// final because a Widget is immutable (remember?)
final bag = {"first": true};
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(title: Text('Stateless ??')),
body: Container(
child: Center(
child: GestureDetector(
child: Container(
width: 50.0,`enter code here`
height: 50.0,
color: bag["first"] ? Colors.red : Colors.blue,
),
onTap: (){
bag["first"] = !bag["first"];
//
// This is the trick
//
(context as Element).markNeedsBuild();
}
),
),
),
);
}
}
Between us, when you are invoking the setState() method, the latter
ends up doing the very same thing: _element.markNeedsBuild().
No. That's the whole point of StatelessWidget: It doesn't have a state.
Only StatefulWidget has a state, and therefore only it has a setState.
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
Hi,
Below code example is taken from when we create a new project in flutter.
Question:
_MyHomePageState will rerender as soon as _incrementCounter is pressed. This will rerender appBar, body, and FloatingActionButton (build method which is costly). Am I right? If right, the only thing that should rerender is a body with text.
How can I separate Widgets that needs re-rendering only? Means separating Stateless and Stateful in the below code. I hope you get my point?
Thanks
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Hot reload'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
);
}
}
Flutter will determine which Widgets need to be recreated or rebuilt, and only recreate / rebuild those.
IIRC, on each setState() (or animation tick, or other re-render), Flutter traverses the Widget tree and compares the before and after state of each Widget tree branch. A stateful widget is only rebuilt if its state has actually changed, and only changed stateless Widgets will be recreated. So in your case, _MyHomePageState is rebuilt, but only the second Text widget is recreated.
See
https://www.youtube.com/watch?v=dkyY9WCGMi0&t=171s
for a far more detailed explanation of Widgets (and underlying elements and render boxes).
I'm learning Flutter, and I'm starting from the very basics. I'm not using MaterialApp. What's a good way to set the background color of the whole screen?
Here's what I have so far:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new Center(child: new Text("Hello, World!"));
}
}
Some of my questions are:
What's a basic way to set the background color?
What exactly am I looking at, on the screen? Which code "is" the background? Is there a thing to set the background color on? If not, what's a simple and appropriate "simple background" (in order to paint a background color).
Thanks for the help!
The code above generates a black screen with white text:
You can set background color to All Scaffolds in application at once.
Just set scaffoldBackgroundColor: in ThemeData:
MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(scaffoldBackgroundColor: const Color(0xFFEFEFEF)),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
I think you can also use a scaffold to do the white background. Here's some piece of code that may help.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Testing',
home: new Scaffold(
//Here you can set what ever background color you need.
backgroundColor: Colors.white,
),
);
}
}
Here's one way that I found to do it. I don't know if there are better ways, or what the trade-offs are.
Container "tries to be as big as possible", according to https://flutter.io/layout/. Also, Container can take a decoration, which can be a BoxDecoration, which can have a color (which, is the background color).
Here's a sample that does indeed fill the screen with red, and puts "Hello, World!" into the center:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new Container(
decoration: new BoxDecoration(color: Colors.red),
child: new Center(
child: new Text("Hello, World!"),
),
);
}
}
Note, the Container is returned by the MyApp build(). The Container has a decoration and a child, which is the centered text.
See it in action here:
There are many ways of doing it, I am listing few here.
Using backgroundColor
Scaffold(
backgroundColor: Colors.black,
body: Center(...),
)
Using Container in SizedBox.expand
Scaffold(
body: SizedBox.expand(
child: Container(
color: Colors.black,
child: Center(...)
),
),
)
Using Theme
Theme(
data: Theme.of(context).copyWith(scaffoldBackgroundColor: Colors.black),
child: Scaffold(
body: Center(...),
),
)
You should return Scaffold widget and add your widget inside Scaffold
Such as this code:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Center(child: new Text("Hello, World!"));
);
}
}
Scaffold(
backgroundColor: Constants.defaulBackground,
body: new Container(
child: Center(yourtext)
)
)
It's another approach to change the color of background:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: Scaffold(backgroundColor: Colors.pink,),);
}
}
On the basic example of Flutter you can set with backgroundColor: Colors.X of Scaffold
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
backgroundColor: Colors.blue,
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add_circle),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
I think you need to use MaterialApp widget and use theme and set primarySwatch with color that you want. look like below code,
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
home: Scaffold(
backgroundColor: Color(
0xBF453F3F),
and done :)
You can just put the six digit hexa after (0xFF**......**):
return Scaffold(
backgroundColor: const Color(0xFFE9ECEF),
.....) } )
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Your App',
theme: ThemeData(
scaffoldBackgroundColor: Colors.black,
),
home HomeScreen(),
);
}
}
Sample code:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Sample App'),
backgroundColor: Colors.amber, // changing Appbar back color
),
backgroundColor: Colors.blue, // changing body back color
),
),
);
}
As sirelon suggested, add scaffold color in the theme like this,
theme: new ThemeData(scaffoldBackgroundColor: const Color(0xFFEFEFEF)),
or can give color to individual scaffold like this
Scaffold(
backgroundColor: Color(0xFFF1F1F1),
...
);
Try the following code:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
scaffoldBackgroundColor: Colors.white, // Change the background color of all Scaffold widgets of your app here
),
home: const Scaffold(
body: Center(child: Text("Hello, World!")),
backgroundColor: Colors.white, // Change the background color of this Scaffold widget here
),
);
}
}