flutter box constraints not propagating to child as expected - flutter

I have learned that to make a Text wrap, you have to wrap it inside a Flexible() and set softWrap: true.
I have a ListView() with items generated by the following code:
return Container(
constraints: const BoxConstraints(maxWidth: 300),
child: Row(mainAxisSize: MainAxisSize.min, children: [
Checkbox(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap),
GestureDetector(
onTap: () {},
child: Container(
color: Colors.white,
child: Row(mainAxisSize: MainAxisSize.min, children: [
Icon(getCustomIcon(name: f.icon), size: 20, color: Colors.black),
const SizedBox(width: 6),
Flexible(
child: Text(f.name,
softWrap: true, style: TextStyle(fontSize: 14))),
const SizedBox(width: 6),
]),
))
]),
);
The Container should have a maximum width of 300 (see the outer BoxConstraints), but the innermost Text() node does not wrap and overflows.
Somewhere in here the box constraints get lost, but I don't understand where.
Note: I removed UI non-relevant code like onTap/onChange/...

After some more testing around I was able to solve the problem myself.
The problem is wrapping a row inside a row (even with other containers in-between) removes the constraints.
The solution is to put a Flexible/Expanded as the child of the parent row:
// innerRow is unconstrained
Row( children: [
...otherElements,
Row() // innerRow
]);
// innerRow is constrained
Row( children: [
...otherElements,
Flexible( // Flexible or Expanded tells the child to fill in the remaining space.
child: Row() // innerRow
)
]);

try :
Wrap your Container with either Row() or Center().
here is Code :
return Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 300),
child: Row(mainAxisSize: MainAxisSize.min, children: [
Checkbox(
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
onChanged: (bool? value) {},
value: true,
),
GestureDetector(
onTap: () {},
child: Container(
color: Colors.white,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.abc,
size: 20, color: Colors.black),
const SizedBox(width: 6),
Flexible(
child: Text("f.name",
softWrap: true,
style: TextStyle(fontSize: 14))),
const SizedBox(width: 6),
]),
))
]),
),
);

Related

How to fix Bottom Overflowed by 10 Pixels?

As you can see in the these two photos below, this problem happened only when the address contains many words, if the address contains fewer words I don't see any issues, I got stuck here and can't think anymore :)
what shall I do in this case, please?
Code:
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
UserAvatarView(
urlPrefix: serverUrl,
url: null,
cornerRadius: 60,
size: 20),
const SizedBox(width: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
order.service.name,
style: Theme.of(context).textTheme.titleMedium,
),
Text(
"${(driverDistance / 1000).round()} KM away",
style: Theme.of(context).textTheme.labelMedium,
)
],
),
const Spacer(),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: CustomTheme.primaryColors.shade200,
borderRadius: BorderRadius.circular(12)),
child: Text(
NumberFormat.simpleCurrency(name: order.currency)
.format(order.costBest),
style: Theme.of(context).textTheme.headlineMedium,
),
)
],
),
const Divider(),
...order.addresses.mapIndexed((e, index) {
if (order.addresses.length > 2 &&
index > 0 &&
index != order.addresses.length - 1) {
return const SizedBox(
width: 1,
height: 1,
);
}
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.all(0),
child: Icon(
getIconByIndex(index, order.addresses.length),
color: CustomTheme.neutralColors.shade500,
),
),
Expanded(
child: Text(e,
overflow: TextOverflow.visible,
style: Theme.of(context).textTheme.bodySmall),
),
if (index == order.addresses.length - 1)
Text(
order.durationBest == 0
? ""
: durationToString(
Duration(seconds: order.durationBest)),
style: Theme.of(context).textTheme.bodySmall)
],
).pOnly(right: 0),
if (index < order.addresses.length - 1)
DottedLine(
direction: Axis.vertical,
lineLength: 25,
lineThickness: 3,
dashLength: 3,
dashColor: CustomTheme.neutralColors.shade500)
.pOnly(left: 10)
],
);
}).toList(),
const Spacer(),
Row(
children: order.options
.map((e) => OrderPreferenceTagView(
icon: e.icon,
name: e.name,
))
.toList()),
ElevatedButton(
onPressed: !isActionActive
? null
: () => onAcceptCallback(order.id),
child: Row(
children: [
const Spacer(),
Text(S.of(context).available_order_action_accept),
const Spacer()
],
).p4())
.p4()
],
),
Photo of a few address words:
Photo of many address words:
Try to wrap your Text() widget with a Flexible(). This should size your widget to make the Text fit.
More here
So i fixed it by adding maxLines and added softWrap and set it to true, (thanks to #Marcel Dz) for his suggestion, but it doesn't work with only Wrap the text with Flexible.
The problem is that the address is changeable, every address has a different number of words, when the address is long it's mean more words and these words are pushing the Button to the bottom because there's no more free space to show the full words of address.
here is the piece of code that i modified:
Expanded(
child: Text(e,
overflow: TextOverflow.visible,
maxLines: 3,
softWrap: true,
style: Theme.of(context).textTheme.bodySmall),
),
Another solution with Flexible:
Flexible(
child: Text(e,
overflow: TextOverflow.visible,
maxLines: 3,
softWrap: true,
style: Theme.of(context).textTheme.bodySmall),
),
Result:
Now it's working perfectly, and i can have as many words as i need, both Expended and Flexible can be used.

How to properly align widgets using flex property in flutter

I'm trying to make a footer and I want everything to appear Centered with even space between these three widgets in the below code.
Container(
margin: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
child: Row(
children: <Widget>[
const Expanded(
flex: 1,
child: Text(
'All Right Reserved',
style: TextStyle(fontSize: 10),
)),
Expanded(
flex: 3,
child: Row(
children: <Widget>[
FooterItem(
title: 'Twitter',
onTap: () {},
),
FooterItem(
title: 'Instagram',
onTap: () {},
),
FooterItem(
title: 'WhatsApp',
onTap: () {},
),
],
),
),
const Expanded(
flex: 1,
child: Text(
'All Right Reserved',
style: TextStyle(fontSize: 10),
)),
],
),
)
I tried using flex as seen in the above code but it doesn't align at the center and no even space as seen in the below screenshot. How to fix this?
You can remove all Expanded and use mainAxisAlignment in parent Row:
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[]
)

How to solve for 'text overflow.ellipse' in flutter?

I am unable to make my text stop extending the screen and overflowing. My code is as follows:
class OrderTileDisplay extends StatelessWidget {
final MenuOrderData orderItem;
final editable;
OrderTileDisplay(this.orderItem, {this.editable = true});
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
GestureDetector(
onTap: (){},
child: Container(
color: Colors.transparent,
margin: EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
orderItem.quantity.toString() + 'x',
style: Title16,
),
SizedBox(
width: 8,
),
Text(
orderItem.name, // OVERFLOWS WHEN IT IS A LONGER SENTENCE
style: Title18bold,
overflow: TextOverflow.ellipsis,
),
],
),
Row(
children: [
editable? Icon(Icons.edit, color: Colors.grey[200], size: 20,) : Container(),
SizedBox(width: 8,),
Text("£" + Provider.of<CP>(context).getTotalForItem(orderItem).toStringAsFixed(2),
style: Title18bold,),
],
),
],
),
),
),
Container(... and other stuff)
I have tried putting Text inside a container then Expanded widget but I keep getting errors. Not sure how to solve it.
Try to wrap your Row and Text inside a Flexible:
Flexible( //flexible here
child: Row(
children: [
Text(
orderItem.quantity.toString() + 'x',
style: Title16,
),
SizedBox(
width: 8,
),
Flexible( //and here
child: Text(
orderItem.name, // no more overflow
style: Title18bold,
overflow: TextOverflow.ellipsis, //working as expected
),
),
],
),
),
As the documentation states, TextOverflow says how overflowing text should be handled, but it will not work if it's parent don't have a fixed size. In this case, Flexible is been used to restrict the total size of the text to prevent overflow, when it reaches a very large width.

How to adjust TextField width?

I'm re-writing a simple app which calculates averages. However, I have a hard time with a TextField. I would like it to be exactly as on a first screenshot.
The TextField's width is stretched, I don't want that. I want it to be exactly as it is on the screenshot.
Desired look:
What I have:
Code:
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
class ArithmeticAverageScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('arithmetic_average_title').tr(),
),
body: Container(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Card(
child: Container(
padding: EdgeInsets.symmetric(vertical: 20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.help),
title: Text('arithmetic_average_help').tr(),
subtitle: Text('arithmetic_average_help_content').tr(),
)
],
),
)
),
SizedBox(height: 16.0),
Card(
child: Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text('arithmetic_average_your_grades', style: Theme.of(context).textTheme.headline5).tr(),
SizedBox(height: 16.0),
Text('arithmetic_average_grades_one_at_a_time', style: Theme.of(context).textTheme.headline6,).tr(),
SizedBox(height: 16.0),
Text('arithmetic_average_grade', style: Theme.of(context).textTheme.subtitle2).tr(),
TextField()
],
),
),
)
],
),
)
);
}
}
This will help you make generic width on all devices, so here width * 0.3 means it will take 30% of the screen width
Container(
width: MediaQuery.of(context).size.width * 0.3,
child: TextField(),
)
Use Row Widget, and put Expanded Widget as child Widget and inside that put your widgets, as Expanded will take up equal space.
return Row(
children: [
Expanded(
child: TextField();
),
Expanded(
child: Button();
)
],
);
When ever you want to play with height and width you can use the widget Container.If you want to play with a property which cannot found in the widget you are using wrap it with a widget with that property will help you.
Container(
margin: const EdgeInsets.only(right: 150),
child: new TextField(
decoration: new InputDecoration(
hintText: 'Grade',
)
)
)
You can try to wrap your TextField and Button with two Flexible widgets and apply desired proportions, e.g. 1:2 which would give you following result:
Row(
children: [
Flexible(
flex: 1,
child: TextField(),
),
Flexible(
flex: 2,
child: RaisedButton(
child: Text('Hello'), onPressed: () {}),
)
],
)
],
You can also replace the first Flexible with SizedBox and set an exact value, e.g:
Row(
children: [
SizedBox(
width: 100.0,
child: TextField(),
),
Flexible(
flex: 2,
child: RaisedButton(
child: Text('Hello'), onPressed: () {}),
)
],
)
],
TextField doesn't have an intrinsic size (width) constraint so it will always try to occupy all horizontal space. Flexible allows to constraint it to desired width in a Row.
Full example on DartPad.

Is there a way to align a widget to the far right of a row in Flutter?

I have a row in Flutter with two widgets. I'm trying to keep the first widget centered in the middle of the screen and the second widget forced to the far right of the screen.
I've tried using Spacer(). This results in the app returning a blank screen.
I've also tried using Expanded. This sends the second widget off the screen completely.
Trying mainAxisAlignment: MainAxisAlignment.spaceBetween did not seem to have any effect.
#override
Widget build(BuildContext context) {
return new Container(
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Container(
child: new GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Column(
children: <Widget>[
SizedBox(height: 40.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Column(
children: <Widget>[
new Container(
child: Row(
mainAxisAlignment:MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(),
Container(
child: Text(
'Profile',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Lato',
color: Colors.white,
fontSize: 50.0,
fontWeight: FontWeight.w700,
),
),
),
Container(
child: IconButton(
icon: Icon(
Icons.settings,
color: Colors.white,
size: 30.0,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OnBoarding()),
);
}),
),
]),
),
),
],
),
],
),
You can use a Row with an Expanded child that contains a Stack. Centre your text with Center and position the icon with Positioned, like so:
[...]
child: Column(
children: <Widget>[
SizedBox(height: 40.0),
Row(
children: <Widget>[
Expanded(
child: Stack(
children: [
Center(
child: Text(...),
),
),
Positioned(
right: 8,
child: IconButton(...),
[...]
Simply just add Spacer() between your main text and the Icon you want to the far right.
For example:
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {},
),
Text(
'Random test text',
style: TextStyle(color: Colors.white),
),
Spacer(),
IconButton(
icon: Icon(Icons.more_vert_rounded),
color: Colors.white,
onPressed: () {},
),
],
)
I hope this helps you. And I hope the format of the code is readable. Still getting a hang of stackoverflow comments
I did this and worked in my project
child:Row(
**crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,**
children: [
Icon(MaterialCommunityIcons.comment_outline),
Text("0"),
Icon(Icons.favorite_border),
Text("0"),
],
),
I needed align Icons and Text at right in Row widget
Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end
children: [ // put your widget list and be happy ]
)
)
enter image description here
Use a row with this following structure:
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(),
Container(
child: Text(
'Profile',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Lato',
color: Colors.white,
fontSize: 50.0,
fontWeight: FontWeight.w700,
),
),
),
Container(
child: IconButton(
icon: Icon(
Icons.settings,
color: Colors.white,
size: 30.0,
),
),
),
]
),
what will happen is that the spaceBetween property will divide available space equally between the widgets in the row, so I put an empty Container, and this will force the Text widget to be in the middle of the row and the IconButton in the far end as you desire.
I noticed in your code snippet that you have a Column with a single Row which again contains a single Column , you should eliminate this redundancy to optimize your code and make it easier to debug:
Have you tried setting the mainAxisAlignment of the row to mainAxisAlignment.center?
Imo the easiest way to do this is to create a row with 2 children: The first child is an Expanded Row with all your "main" widgets. The second child is your widget which must be aligned to the end.
Row(
children: [
Expanded(
child: Row(
children: [...mainWidgets...],
),
),
...endWidget...
],
),
Note that Expanded is space-greedy. If you use e.g. MainAxisAlignment.center for your Expanded Row, then your children are drawn across the whole avialable width. If this is not to your liking, Id suggest to wrap the Expanded-Row (not Expanded) inside a Container with "constraints: BoxConstraints(maxWidth: 500)". Obviously Expanded shouldnt be Constrained.
Achieve using Expanded & Align like below inside Row:
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
...some other widgets,
Expanded(
//Expanded will help you to cover remaining space of Row
flex: 1,
child: Align(
//Align with alignment.centerRight property will move the child to righteous inside Expanded
alignment: Alignment.centerRight,
child: const Icon(Icons.arrow_back),
),
),
],
),
Note, the Expanded has to be just inside the Row children: <Widget>[],
othewise suppose you've put the GestureDetector inside Row children: <Widget>[], and inside GestureDetector you have put your Expanded, then it won't
work.
Hope this would help many one.