How to make row/column of non-fixed sized parent fill the whole space - flutter

I am trying to do it with Expanded but I am getting 'RenderFlex children have non-zero flex but incoming width constraints are unbounded.' which is expected because the size of parent is not defined.
Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(
'something',
style: Theme.of(context).primaryTextTheme.headline2,
),
Expanded(
child: Container(),
),
]
)

If your Row is wrapped within an Column widget it will take up all of the available space and give your Row the required Parent width. This will be rendered at the top of the Column.
import 'package:flutter/material.dart';
class TestScreen extends StatelessWidget {
static const routeName = '/testScreen';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: Column(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(
'something',
style: Theme.of(context).primaryTextTheme.headline2,
),
Expanded(
child: Container(),
),
],
),
],
),
);
}
}
If you want the widget to take up entire height as well then wrap it again with an Expanded
import 'package:flutter/material.dart';
class TestScreen extends StatelessWidget {
static const routeName = '/testScreen';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(
'something',
style: Theme.of(context).primaryTextTheme.headline2,
),
Expanded(
child: Container(),
),
],
),
),
],
),
);
}
}
If you do not give the Row this fixed area it will expand indefinitely off the side of your screen
Non Column solution
body: SingleChildScrollView(
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(
'something',
style: Theme.of(context).primaryTextTheme.headline2,
),
Expanded(
child: Container(),
),
],
),
),

Related

ChoiceChip not expanding with IntrinsicWidth

I'm wondering why ChoiceChip is not expanding like ElevatedButton does.
Here is an example: (look at dartpad)
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: MyWidget(),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(children: [
IntrinsicWidth(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ElevatedButton(
child: const Text('Larger Text'),
onPressed: () {},
)),
Expanded(
child: ElevatedButton(
child: const Text('Text'),
onPressed: () {},
)),
],
)),
IntrinsicWidth(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: const [
Expanded(
child: ChoiceChip(
label: Text('Larger Text'),
selected: false,
)),
Expanded(
child: ChoiceChip(
label: Text('Text'),
selected: false,
)),
],
))
]);
}
}
To solve this, let's start by enabling Flutter Inspector, we can see the second IntrinsicWidth width and its children don't fill their parent as the first one (two problems)
Solve 1st problem: IntrinsicWidth children don't fill their parent width
So, the problem is the size of the 2nd IntrinsicWidth's children is not wide/big enough so that it can be full of parent width. Try increasing its width manually by wrapping it in a Container with double.infinity width, like this:
ChoiceChip(
label: Container(width: double.infinity, child: Text('Larger Text')),
selected: false,
)
New result:
Solve 2nd problem: the 2nd IntrinsicWidth don't fill their parent width
Let's leave Column children can have the maximum width as it is (removing all IntrinsicWidth inside its children) and then wrap the Column by an IntrinsicWidth. Complete sample code:
Sample 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 const MaterialApp(
home: Scaffold(
body: MyWidget(),
),
);
}
}
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
#override
Widget build(BuildContext context) {
return IntrinsicWidth(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ElevatedButton(
child: const Text('Larger Text'),
onPressed: () {},
),
),
Expanded(
child: ElevatedButton(
child: const Text('Text'),
onPressed: () {},
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ChoiceChip(
label: Container(width: double.infinity, child: Text('Larger Text')),
selected: false,
),
),
Expanded(
child: ChoiceChip(
label: Container(width: double.infinity, child: Text('Text')),
selected: false,
),
),
],
),
],
),
);
}
}
Final result:
Because under the hood the widgets are designed differently (that's why the names).
I haven't checked the code in detail (you can do that by ctrl + click on Widget Name).
But best guess, visual density is lower in chips for being compact and higher in buttons.
More on technical difference to understand which to use : chips-vs-button

display widget in a center of column

In my page I have a customized Appbar then I want to display a message with icon, and it should be in the center of the page. i mean the customized Appbar is on the top then in the center of the page we have the icon with the message
child: Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Column(children: [
const CustomAppBar("Réglages et paramétrages", true, false,
returnToHistory: true),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment : MainAxisAlignment.center,
children: const [
Icon(Icons.warning, color: Color(0xFFFF9500), size: 100 ,),
],
),
Row(
children: const [
Text(
"be careful",
textAlign: TextAlign.center,)
],
)
],
),
]),
)),
));
you can try doing it this way by using an expanded widget to adjust the flex of the custom appbar and scrollview
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: const CustomAppBar("Réglages et paramétrages", true, false,
returnToHistory: true),
),
Expanded(
flex: 7,
child: Center(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: const [
Icon(
Icons.warning,
color: Color(0xFFFF9500),
size: 100,
),
Text(
"be careful",
textAlign: TextAlign.center,
)
],
),
),
),
),
],
),
),
);
Remove SingleChildScrollView and wrap the inner column with an expanded widget.
You can create custom appbar as widget and provide on Scaffold's appbar. To do this, you need to implements PreferredSizeWidget
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
final String title;
const CustomAppBar({
Key? key,
required this.title,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Text(title),
);
}
#override
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}
And your layout will be
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(title: "Réglages et paramétrages"),
body: SafeArea(
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(Icons.warning, color: Color(0xFFFF9500)),
Text(
"be careful ",
textAlign: TextAlign.center,
)
],
),
]),
),
),
),
);
}
You can find more about ui/layout on flutter dev .

I can't set the height of my container after some limit

import 'package:flutter/material.dart';
void main() => runApp(HomePage());
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
children: [
Container(
color: Colors.blue,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
ButtonBar(
children: <Widget>[
FlatButton(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Center(
child: Text(
"ljsdgnvsdnv",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
),
),
Text(
"sljdvnldnvsdb",
style: TextStyle(fontSize: 15),
),
],
),
height: 60,
width: 600,
color: Colors.orange,
),
onPressed: () {
print("Buton");
},
),
],
)
],
),
),
],
),
),
);
}
}
I can't set the height of my containers after some limit(also the widht of the second container), it doesn't give any errors but at the same time it doesn't change it's height. In flutter inspector their height and widht values are the values which are I assigned but it doesn't look like it. What should I do? (Text are random)
I just tried your code and didn't find any error while running it. But if the error that you are talking about are linked with the size of the container and some limit that you have added, than it's because you are trying to create an widget bigger than the zone that contain the widget.
You should check the limit that you have by trying:
mainAxisSize: MainAxisSize.max,
And than you could give value that are within the zone.

Positioning children widgets at the center and at the end of a Column parent widget

I have to position 2 children widgets inside a Column parent widget. I want one of them to be positioned in the center and the other at the end of the column. What is the best way to do that?
import 'package:flutter/material.dart';
class Screen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Screen'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center, // this is wrong, it positions both the widgets in the center
children: <Widget>[
Text('This text should be at the center of the column'),
Text('This text should be at the end of the column'),
],
),
);
}
}
you can use the Spacer widget like this:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Spacer(),
Text('This text should be at the center of the column'),
Spacer(),
Text('This text should be at the end of the column'),
],
),
);
(EDIT: I changed the code and added grey to mine in order to show a comparison, so you can see what I mean when I say it will be offset by half. You have to increase the font size to see the difference.)
It's not quite as easy as the other answers because the first text has to be centered and if you only use two elements in your Column then no matter what you do it's either going to make the top item be off-center by half the height of the bottom text (as in using only two Expandeds) or the design will be rigid and therefore may not display correctly on different sized devices.
So, the trick is to use three Flexibles (2 Expandeds and a Spacer). Put the Spacer on top. It and the bottom Expanded must have the same flex value in order to center the middle Expanded.
Only then will using "alignment: Alignment.center" give the needed result for the top text.
import 'package:flutter/material.dart';
class CenteringOneItemWithAnotherItemInTheColumn extends StatelessWidget {
const CenteringOneItemWithAnotherItemInTheColumn({
Key key,
}) : super(
key: key,
);
/// Adjust these values as needed
final int sameFlexValueTopAndBottom = 40; // 40%
final int middleFlexValue = 20; // 20%
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Column Alignment Question'),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Spacer(),
const Text(
'Cent',
style: TextStyle(
fontSize: 64,
),
),
const Spacer(),
const Text(
'Bot',
style: TextStyle(
fontSize: 64,
),
),
],
),
Column(
children: <Widget>[
/// The key is to have the Spacer and the bottom Expanded
/// use the same value for flex. That will cause the middle
/// child of the Column to be centered vertically.
Expanded(
flex: sameFlexValueTopAndBottom,
child: Container(
width: 100,
color: Colors.grey[300],
),
),
Expanded(
flex: middleFlexValue,
child: const Align(
alignment: Alignment.center,
child: Text(
'Cent',
style: TextStyle(
fontSize: 64,
),
),
),
),
Expanded(
flex: sameFlexValueTopAndBottom,
child: Container(
color: Colors.grey[300],
child: const Align(
alignment: Alignment.bottomCenter,
child: Text(
'Bot',
style: TextStyle(
fontSize: 64,
),
),
),
),
),
],
),
],
),
);
}
}
Another way is to use an empty SizedBox at the start and the mainAxisAlignment: MainAxisAlignment.spaceBetween,
class Screen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Screen'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(
height: 0.0,
width: 0.0,
),
Text('This text should be at the center of the column'),
Text('This text should be at the end of the column'),
],
),
);
}
}
One of the way could be using Expanded widget along with alignment as for the need
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Screen'),
),
body: Column(
// mainAxisAlignment: MainAxisAlignment.center, // this is wrong, it positions both the widgets in the center
children: <Widget>[
Expanded(child: Container(alignment:Alignment.bottomLeft,child: Text('This text should be at the center of the column'))),
Expanded(child: Container(alignment: Alignment.bottomLeft, child: Text('This text should be at the end of the column'))),
],
),
);
}

Can't find correct layout option for how to use ListView in a custom Widget

I am trying to extract re-use a simple widget that is then referenced in parent widget. The custom widget simply uses a row to layout a textField and a button, and below this I Want to have a listview showing items. I then embed in the customwidget in parent, but it continually throws Error. I have not figured out how to get the custom widget working where I can use ListView or column layout inside. Below is the 2 simplified widgets that demo the issue.
Here is the parent widget, which is where I call the custom widget PlayListControl()
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Playlists'),
),
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
textDirection: TextDirection.ltr,
children: <Widget>[
Container(
alignment: Alignment.center,
margin: EdgeInsets.all(20),
child: Text('Test'),
),
PlayListControl(),
],
),
),
drawer: SideDrawer(),
);
}
}
And here is the playlistcontrol widget.
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 200,
child: TextField(),
),
ButtonTheme(
minWidth: 30,
child: RaisedButton(
textColor: Colors.white,
child: Text('add'),
onPressed: () {},
)),
],
),
),
Expanded(
child: ListView(
children: <Widget>[
Text('Widget 1'),
Text('Widget 2'),
],
),
)
],
),
);
}
}
No matter what I try, it always complains about layout issue related to height. I would have thought wrapping the ListView in Expanded would solve the issue, but it doesn't. Only if I use a container and specify height do I not get the errors, but I want to use whatever available space there is.
How can I get this playlistcontrol() widget to properly render inside a parent control?
you forgot to wrap the first container of PlayListControl in Expanded widget..
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text('My Playlists'),
),
body: Container(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
textDirection: TextDirection.ltr,
children: <Widget>[
Container(
alignment: Alignment.center,
margin: EdgeInsets.all(20),
child: Text('Test'),
),
PlayListControl(),
],
),
),
));
}
}
class PlayListControl extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 200,
child: TextField(),
),
ButtonTheme(
minWidth: 30,
child: RaisedButton(
textColor: Colors.white,
child: Text('add'),
onPressed: () {},
)),
],
),
),
Expanded(
child: ListView(
children: <Widget>[
Text('Widget 1'),
Text('Widget 2'),
],
),
)
],
),
),
);
}
}