How to vertically center a column in Flutter? I have used widget "new Center". I have used widget "new Center", but it does not vertically center my column ? Any ideas would be helpful....
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Thank you"),
),
body: new Center(
child: new Column(
children: <Widget>[
new Padding(
padding: new EdgeInsets.all(25.0),
child: new AnimatedBuilder(
animation: animationController,
child: new Container(
height: 175.0,
width: 175.0,
child: new Image.asset('assets/angry_face.png'),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 6.3,
child: _widget,
);
},
),
),
new Text('We are glad we could serve you...', style: new TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w600,
color: Colors.black87),),
new Padding(padding: new EdgeInsets.symmetric(vertical: 5.0, horizontal: 0.0)),
new Text('We appreciate your feedback ! !', style: new TextStyle(
fontSize: 13.0,
fontWeight: FontWeight.w200,
color: Colors.black87),),
],
),
),
);
}
Solution as proposed by Aziz would be:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//your widgets here...
],
)
It would not be in the exact center because of padding:
padding: EdgeInsets.all(25.0),
To make exactly center Column - at least in this case - you would need to remove padding.
Try:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children:children...)
Try this one. It centers vertically and horizontally.
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
),
)
With Column, use:
mainAxisAlignment: MainAxisAlignment.center
It align its children(s) to center of its parent Space vertically
You control how a row or column aligns its children using the mainAxisAlignment and crossAxisAlignment properties. For a row, the main axis runs horizontally and the cross axis runs vertically. For a column, the main axis runs vertically and the cross axis runs horizontally.
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
While using Column, use this inside the column widget :
mainAxisAlignment: MainAxisAlignment.center
It align its children(s) to the center of its parent Space is its main axis i.e. vertically
or,
wrap the column with a Center widget:
Center(
child: Column(
children: <ListOfWidgets>,
),
)
if it doesn't resolve the issue wrap the parent container with a Expanded widget..
Expanded(
child:Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
),
),
)
Another Solution!
If you want to set widgets in center vertical form, you can use ListView for it.
for eg: I used three buttons and add them inside ListView which followed by
shrinkWrap: true -> With this ListView only occupies the space which needed.
import 'package:flutter/material.dart';
class List extends StatelessWidget {
#override
Widget build(BuildContext context) {
final button1 =
new RaisedButton(child: new Text("Button1"), onPressed: () {});
final button2 =
new RaisedButton(child: new Text("Button2"), onPressed: () {});
final button3 =
new RaisedButton(child: new Text("Button3"), onPressed: () {});
final body = new Center(
child: ListView(
shrinkWrap: true,
children: <Widget>[button1, button2, button3],
),
);
return new Scaffold(
appBar: new AppBar(
title: Text("Sample"),
),
body: body);
}
}
void main() {
runApp(new MaterialApp(
home: List(),
));
}
Output:
CrossAlignment.center is using the Width of the 'Child Widget' to center itself and hence gets rendered at the start of the page.
When the Column is centered within the page body's 'Center Container' , the CrossAlignment.center uses page body's 'Center' as reference and renders the widget at the center of the page
Code
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
title:"DynamicWidgetApp",
home:DynamicWidgetApp(),
));
class DynamicWidgetApp extends StatefulWidget{
#override
DynamicWidgetAppState createState() => DynamicWidgetAppState();
}
class DynamicWidgetAppState extends State<DynamicWidgetApp>{
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
//Removing body:Center will change the reference
// and render the widget at the start of the page
child: Column(
mainAxisAlignment : MainAxisAlignment.center,
crossAxisAlignment : CrossAxisAlignment.center,
children: [
Text("My Centered Widget"),
]
),
),
floatingActionButton: FloatingActionButton(
// onPressed: ,
child : Icon(Icons.add),
),
);
}
}
For me the problem was there was was Expanded inside the column which I had to remove and it worked.
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded( // remove this
flex: 2,
child: Text("content here"),
),
],
)
You could use.
mainAxisAlignment:MainAxisAlignment.center
This will the material through the center in the column wise.
`crossAxisAlignment: CrossAxisAlignment.center'
This will align the items in the center in the row wise.
Container( alignment:Alignment.center, Child: Column () )
Simply use.
Center ( Child: Column () )
or rap with Padding widget . And adjust the Padding such the the column children are in the center.
You can also wrap the Column widget by Align.
Align(
alignment: Alignment.center,
child: Column(
children: [
Container(
width: 300,
margin: const EdgeInsets.fromLTRB(0, 70, 0, 0),
child: TextFormField(decoration: const InputDecoration(hintText: "First Name"))
),
...
]
)
)
Checkout this website for different ways of centering a widget: Link
In Addition, If you used
mainAxisAlignment: MainAxisAlignment.start
for centering all children but you still one of the children to be centered , Simply use Center() widget on the children.
Related
Is there any way to achieve text baseline with VericalDivider() where the Rows() under the Column() and required IntrinsicHeight() to make the VerticalDiver() render properly.
Meanwhile, look like there is limitation around CrossAxisAlignment.baseline and IntrinsicHeight https://github.com/flutter/flutter/issues/71990#issuecomment-747141796
From the picture below, I can't use CrossAxisAlignment.baseline with IntrinsicHeight Widget so the text that has different size will look something like this. But if I remove IntrinsicHeight the VericalDivider Widget will not render. (Height = 0)
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("hey"),
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(child: Text("aaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")),
VerticalDivider(
width: 50,
thickness: 50,
),
Expanded(child: Text("bbbbbb", style: TextStyle(fontSize: 30),))
],
),
),
],
),
);
}
}
So i tried to make my TextWidget aligned to left but when i put TextWidget above ( before ) TextFieldWidget it's automatically become centered following with the TextFieldWidget, here my code
import 'package:flutter/material.dart';
void main() {
runApp(new MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Center(
child: Text("SQLite Application"),
),
),
body: Column(
children: <Widget>[
SizedBox(
height: 20,
),
Text("Name of Things"),
TextField()
],
),
),
);
}
}
and here is the result :
Code Output
Is there a solve to make the TextWidget to aligned to the left ? I've tried to use TextAlign.left on TextWidget but it wont change.
Use
crossAxisAlignment: CrossAxisAlignment.start,
on the Column
You need to set the mainAxisAlignment to Start
Column(
crossAxisAlignment: CrossAxisAlignment.start
In case you want to place the contents at the Right Side, you can use
Column(
crossAxisAlignment: CrossAxisAlignment.end
just add
Column(
crossAxisAlignment: CrossAxisAlignment.start,
the result
You put your text inside Column widget. Column by default crossAxisAlignment is centre. That's why your text is always on centre.
for example
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:const [
SizedBox(
height: 20,
),
Text("your text....!"),
TextField()
],
),
And if you wanna align text without Column, use Align with with alignment.topleft. It will move on left side
Align(
alignment: Alignment.topLeft,
child: Text("Name of Things", textAlign: TextAlign.left,),
),
How can I make the red box to use full width and put the button to the very right of the screen when wrapping?
Also I want spaceBetween if the button is not wrapping, but it does not work:
This is what I have sofar:
Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Container(
color: Colors.red,
child: Wrap(
alignment: WrapAlignment.end,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Please wrap on small screens",
style: Theme.of(context).textTheme.bodyText1,
),
),
),
TextButton(
onPressed: () {},
child: Text("Bearbeiten"))
],
),
),
),
// ...
]
)
Updated
Finally, I manage to solve your problem. Probably is not a canonic way, but it's working.
You need to compute the total width of your content in order to compare it with the width of the screen (the width is the width of the widgets, plus space you want between widgets, plus padding from both sides).
With that, you are able to know when you need to change the layout, and you can apply the layout you want to each case.
Here I leave the code:
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey textKey = GlobalKey();
final GlobalKey buttonKey = GlobalKey();
double widthLimit = double.infinity;
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
final textBox = textKey.currentContext.findRenderObject() as RenderBox;
final buttonBox = buttonKey.currentContext.findRenderObject() as RenderBox;
widthLimit = textBox.size.width + buttonBox.size.width + 8 + 16 * 2;
});
}
Widget _wrap(bool spaceBetween, Widget child) => spaceBetween
? child
: Align(
alignment: Alignment.centerRight,
child: child,
);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(
width: double.infinity,
padding: EdgeInsets.all(16.0),
color: Colors.red,
child: Builder(builder: (context) {
final screenWidth = MediaQuery.of(context).size.width;
final spaceBetween = screenWidth >= widthLimit;
return Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.spaceBetween,
children: [
Text("Please wrap on small screen small screen", key: textKey),
_wrap(
spaceBetween,
TextButton(
key: buttonKey,
onPressed: () {},
child: Text("Bearbeiten"),
)),
],
);
}),
),
),
);
}
}
Old Answer
I am going to take a couple of premises from your screenshots:
The Wrap doesn't have to take the full width by default
You only want to go to two lines when there is not enough space in the device screen.
With that, you can make what you want with this code:
Container(
padding: EdgeInsets.all(16.0),
color: Colors.red,
child: Wrap(
spacing: 8,
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.end,
children: [
Text("Please wrap on small screen"),
TextButton(onPressed: () {}, child: Text("Bearbeiten")),
]),
),
I added the spacing property to the Wrap to provide space as you wanted when both widgets are at the same line. Also, I set the alignment of the Wrap to end to align as you want.
When there is not enough space on the screen, the widget is going to move to a new line and align to the end. As the first widget is longer than the wrapped one and, as I said in the premises, we don't need to take the full width of the screen, Wrap will adapt to keep things aligned properly.
I want overlay a widget over the bottom widget to hide it. hence I use stack. I don't know the bottom widget size so I can't give top widget fixed size.
what I have:
what I want to achieve:
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Winner: ',
style: TextStyle(fontSize: 34),
),
Stack(
children: [
Text('YOU!!!', style: TextStyle(fontSize: 34)),
Container(
color: Colors.amber,
)
],
),
],
),
This is simplified version of what I want to achive. I have to use Row and assume Texts are any widget with any size.
Stack sizes its children based on the Constraint it receives from parent not based on children sizes.
how can I overlay top widget with exact size of bottom widget?
To know the size of your widget and apply things depending on this, you can use GlobalKey like this GlobalKey key;. Initialize it in your initSate and listen to it's size
GlobalKey key;
double yourWidgetWidth;
double yourWidgetHeight;
#override
initState() {
// .... other stuffs
key = GlobalKey();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
yourWidgetWidth = containerKey.currentContext.size.width;
yourWidgetHeight = containerKey.currentContext.size.height;
}
});
}
And with yourWidgetWidth and yourWidgetHeight you can achieve what you want
Edit
Here is a concept of what am trying to explain
// In variable declaration scope
GlobalKey youTextKey = GlobalKey();
ValueNotifier widthNotifier = ValueNotifier(0);
ValueNotifier heightNotifier = ValueNotifier(0);
// In initState
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
widthNotifier.value = youTextKey.currentContext.size.width - 1.0;
heightNotifier.value = youTextKey.currentContext.size.height - 5.0;
}
});
// Your row
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Winner: ',
style: TextStyle(fontSize: 34),
),
Stack(
children: [
Text('YOU!!!', style: TextStyle(fontSize: 34), key: youTextKey,),
ValueListenableBuilder(
valueListenable: widthNotifier,
builder: (context, width, _) {
return ValueListenableBuilder(
valueListenable: heightNotifier,
builder: (context, height, _) {
return Container(
width: width,
height: height,
color: Colors.amber,
);
},
);
},
),
],
),
],
)
Using Positioned.Fill solved the problem:
Positioned.Fill Creates a Positioned object with [left], [top], [right], and [bottom] set to 0.0 unless a value for them is passed.
so the Positioned child get stretched to the edges of the stack's biggest child.
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Winner: ',
style: TextStyle(fontSize: 34),
),
Stack(
children: [
Text('YOU!!!', style: TextStyle(fontSize: 34)),
Positioned.fill(
child: Container(
color: Colors.amber,
),
)
],
),
],
),
I have added a few widgets inside the ListView. So that I can scroll all widgets. Now I required to add one more widget to the ListView to load the list of comments. I can not add the ListView inside the ListView. And moreover, I do not require the separate scroll for my comments. It should be scroll along with the widgets inside the ListView. So I planned to add the Column instead of ListView. Could any help to add my comments dynamically in the Columns?
new Expanded(
child:
new ListView(
shrinkWrap: true,
children: <Widget>[
// Title
new Padding(padding: const EdgeInsets.only(
top: 10.00, left: 10.00),
child: new Text(
_feed.title, textAlign: TextAlign.start,),
),
// content
new Container(
child: new Text(
_feed.content, textAlign: TextAlign.start,),
),
// Comments List will go here
],
),
),
If you have the comments data already, simply create a List, then pass it to the children property of the Column. Something like:
var commentWidgets = List<Widget>();
for (var comment in comments) {
commentWidgets.Add(Text(comment.text)); // TODO: Whatever layout you need for each widget.
}
…
new Expanded(
child:
new ListView(
shrinkWrap: true,
children: <Widget>[
// Title
new Padding(padding: const EdgeInsets.only(
top: 10.00, left: 10.00),
child: new Text(
_feed.title, textAlign: TextAlign.start,),
),
// content
new Container(
child: new Text(
_feed.content, textAlign: TextAlign.start,),
),
// Comments List will go here
Column(children: commentWidgets,),
],
),
),
If you don't have the comments data already and need to fetch it, use a FutureBuilder to build the UI once the future completes.
Another way:
return Column(
children: [
for(String item in list) Text(item);
]);
You can also mix static and dynamic fields eaisly in this case:
return Column(
children: [
for(String item in list) Text(item),
Text("Static text control"),
]);
By maintaining a reference to the Column object, the .children field/property can be referenced after the Column object has been declared - like so:
Column someColumn = Column(
children: [],
);
someColumn.children.add(Text('Hello 123'));
Currently(2021-06), Flutter 2.x implemented null-safe.
The answer from #Gene Bo should work but needs little modification.
This should work.
var pwdWidgets = <Widget>[];
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: this.pwdWidgets,
),
ElevatedButton(
onPressed: (){
setState((){
this.pwdWidgets.add(Text("Hello World"),);
});
},
child: Text("click me"),
),
In Addition to #Derek Lakin's Answer which worked for me too, it is also required to call setState(), if you need to update the comments and reload.
var commentWidgets = List<Widget>();
for (var comment in comments) {
commentWidgets.Add(Text(comment.text)); // TODO: Whatever layout you need foreach widget.
}
setState(() {
});
import 'package:flutter/material.dart';
class LoginRegisterPage extends StatefulWidget {
#override
_LoginRegisterPageState createState() => _LoginRegisterPageState();
}
class _LoginRegisterPageState extends State<LoginRegisterPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("App"),
),
body: new Container(
margin: EdgeInsets.all(15.0),
child: new Form(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: createInputs() + createButtons(),
),
),
),
);
}
List<Widget> createInputs(){
return{
SizedBox(height: 10.0),
logo(),
SizedBox(height: 20.0),
new TextFormField(
decoration: new InputDecoration(labelText: 'Email'),
),
SizedBox(height: 10.0),
new TextFormField(
decoration: new InputDecoration(labelText: 'Passwors')
),
SizedBox(height: 20.0),
};
}
Widget logo(){
return new Hero(
tag:'hero',
child: new CircleAvatar(
backgroundColor:Colors.transparent,
radius: 110.0,
child: Image.asset("images\logo.PNG"),
),
);
}
List<Widget> createButtons(){
return{
new RaisedButton(
child: new Text("Login", style: new TextStyle(fontSize: 20.0),),
textColor: Colors.pink,
onPressed: () {
},
),
new FlatButton(
child: new Text("Already not have an account?", style: new TextStyle(fontSize: 14.0),),
textColor: Colors.white,
onPressed: () {
},
)
};
}
}
Yes you can add dynamic child on column widgets.
class CategoriesItemWidget extends StatelessWidget {
final List<String> list;
const CategoriesItemWidget({Key? key, required this.list})
: super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: list
.map((string) => Text(string))
.toList(),
);
}
}