How to fix Bottom Overflowed by 10 Pixels? - flutter

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.

Related

Align a text in Flutter to make a restaurant menu

I'm trying to make a menu for a reastaurant like this one : -
I'm using Flutter and this is my code:
return Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Row(
children: [
Expanded(child: Text( text, style: style, )),
const SizedBox( width: 15 ),
Text( '\$ $price', style: style,),
],
),
),
Divider( color: Colors.white.withOpacity( 0.5 ),),
],
);
But this is the result that I'm getting : -
Please, any help will be welcome.
And thanks in advance.
The result that you want to achieve can be done just by using the row widget, you don't have to wrap it up with ListTile. I am writing the code snippet of Row widget for you. You can copy paste it and it will work. Additionally I see that you are generating it in the column widget. If you have a dynamic array then I suggest that you use ListView Divider instead. It will have a divider to add between your rows as well. You can find more about it on flutter official documentation.
Row(
children:[
//You may add some padding to Text for better looking UI.
Text("Chicken Masala"),
Expanded(child:Divider()),
Text("180")
])
Just replace your column's children with this row and you will be able to see it.
I solved your issue like this:
Output of your issue : -
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Row(
children: [
const Text(
'Cheese Burger',
),
Expanded(child: Text('.' * 100, maxLines: 1)),
const Text(
'\$ 10',
),
],
),
),
const SizedBox(
height: 10,
),
ListTile(
title: Row(
children: [
const Text(
'Chicken Masala Soup',
),
Expanded(child: Text('.' * 100, maxLines: 1)),
const Text(
'\$ 10',
),
],
),
),
],
),
#Ramji, #Dhruvil Patel, I try your code and it work fine, but it was making an overflow when the text was long, so I made some changes in your example and I got what I was looking for.
Thanks a lot for you help.
Here is what I dit.
return SizedBox(
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded( child: Text( text, style: style, maxLines: 2, overflow: TextOverflow.ellipsis, ) ),
],),
Row(
children: [
Expanded(
child: Text(
'.' * 150,
style: style,
maxLines: 1,
overflow: TextOverflow.fade,)),
SizedBox(
width: 80,
child: Text(
'\$ $price',
style: style,
textAlign: TextAlign.right,)),
],
),
// Divider( color: Colors.white.withOpacity( 0.5 ),),
],
),
);

flutter box constraints not propagating to child as expected

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),
]),
))
]),
),
);

How to build widget with certain order?

Hi I'm trying to create a widget of container that contain a list of profile picture and person name (max 3 people). I manage to build them but the problem is I wanted to make the current logged in user to always be on the left side, not on the middle or right side. How can I achieved it ? Thanks before
Here's my code:
if (ticketData['solver_id'] != null && ticketData['solver_id'].isNotEmpty) {
await Future.forEach(ticketData['solver_id'], (solver) async {
solverWidgets.add(
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BuildRoundedRectProfile(
height: 40,
width: 40,
name: solverTicket[solver]['nickname'],
profileLink: solverTicket[solver]['profile_picture_link'] ?? '',
),
SizedBox(height: 3),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Text(
solverTicket[solver]['nickname'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: weight600Style.copyWith(
color: primaryColor,
fontSize: 13,
),
),
),
],
),
),
);

TextSpan's text doesn't show if it overflows

That's how it looks when I have a WidgetSpan and a TextSpan, and the text inside the TextSpan is too long:
problem
A similar question has already been asked here TextSpan's text doesn't show if it overflows and is placed after WidgetSpan, but the one answer isn't suitable for my problem.
I have two Text.rich() widgets (which each host one WidgetSpan and one TextSpan) inside an Expanded widget, both Expanded with flex:1, because I want them to be the same size and take as much space as they can. That's why a row is not an option, you can't (as far as I know) put two rows side by side, at this happens...
using rows
This is how it's supposed to look like, just with the TextOverflow.ellipsis, if the text is too long:
target UI
Here is my code:
Row(
children: [
Expanded(
flex: 1,
child: Text.rich(
TextSpan(children: [
WidgetSpan(
child: Container(
margin: const EdgeInsets.only(right: 4.0),
child: SvgPicture.asset("assets/icons/building.svg", color:
htLightGrey),
),
),
TextSpan(
text: incident.building.name,
style: const TextStyle(
fontWeight: FontWeight.normal,
fontSize: 16.0,
color: htLightGrey, /*overflow: TextOverflow.ellipsis*/
),
),
]),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Expanded(
flex: 1,
child: incident.department != null
? Text.rich(
TextSpan(children: [
WidgetSpan(
child: Container(
margin: const EdgeInsets.only(right: 4.0),
child: SvgPicture.asset("assets/icons/department.svg",
color: htLightGrey),
),
),
TextSpan(
text: incident.department!.name,
style: const TextStyle(fontWeight: FontWeight.normal,
fontSize: 16.0, color: htLightGrey, overflow:
TextOverflow.ellipsis),
),
]),
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
: const SizedBox.shrink(),
)
],
)
To achieve your target Ui, use the Wrap widget instead of the Row widget. Here, when the contents of the widget overflow/exceed it will break it to the next line, hence you'll achieve your target Ui.
While we like to archive this UI, we are using Row as parent widget, which is perfect. Then we can split the row into tree part, left two part will get same and maximum available width. For this scenario, widget structure as follows.
Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.green,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, //start from left
children: [
buildItem(
text:
"incident.buildi cident.buildi cident.buildi cident.buildi cident.building.name"),
buildItem(text: "incide ing.ssss"),
],
),
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.red,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildItem(text: "i ent.building.name"),
buildItem(text: "incident.building.ssss"),
],
),
),
),
IconButton(
onPressed: () {},
iconSize: 33,
icon: Icon(Icons.arrow_right),
),
],
),
And inside Text.rich add use alignment: PlaceholderAlignment.middle, on WidgetSpan to set the middle.
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.start,
And you will get
I am using extra container to point the UI, simply remove the container from the column. Also, you can use Row instead of Rich Text.
Test widget
class _TestGroundState extends State<TestGround> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.green,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start, //start from left
children: [
buildItem(
text:
"incident.buildi cident.buildi cident.buildi cident.buildi cident.building.name"),
buildItem(text: "incide ing.ssss"),
],
),
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.red,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildItem(text: "i ent.building.name"),
buildItem(text: "incident.building.ssss"),
],
),
),
),
IconButton(
onPressed: () {},
iconSize: 33,
icon: Icon(Icons.arrow_right),
),
],
),
],
));
}
Text buildItem({
required String text,
}) {
return Text.rich(
TextSpan(
children: [
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Container(
child: Icon(Icons.ac_unit),
),
),
TextSpan(
text: text,
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: 16.0,
),
),
],
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.start,
);
}
}
More about flutter layout

How to dynamically change container size based on text inside?

I'm displaying a list of Animated Containers which originally has a certain maxLines of text. When the user clicks on the container, I want the container to expand to perfectly fit the entire text
Here's my simplified code:
AnimatedContainer(
height: containerHeight,
curve: Curves.easeOut,
duration: Duration(milliseconds: 400),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(searchBooksList[index].title),
Text('By ${searchBooksList[index].author}'),
Expanded(
child: Text(
'\n${searchBooksList[index].description}',
overflow: TextOverflow.ellipsis,
maxLines: searchBooksList[index].expanded ? 50 : 7,
)
),
],
),
)
When the user clicks on the container:
onTap: () {
setState(() {
searchBooksList[index].expanded = !searchBooksList[index].expanded;
});
},
Currently, I'm explicitly mentioning the height of the container based on the length of the text
double len;
if(searchBooksList[index].description.length <= 500)
len=0.3;
else if (searchBooksList[index].description.length > 500 && searchBooksList[index].description.length<=750)
len = 0.6;
else if(searchBooksList[index].description.length > 750 && searchBooksList[index].description.length<=1000)
len=0.66;
else if(searchBooksList[index].description.length > 1000 && searchBooksList[index].description.length<=1500)
len=1.0;
else if(searchBooksList[index].description.length>=1500)
len=1.2;
double containerHeight = searchBooksList[index].expanded ? 1000 * len
: 1000 * 0.25;
Here's what's happening now:
But this leaves empty lines at the end for some text. Is there a better way to fit the text without resizing the text?
EDIT:
SingleChildScrollView(
child: Container(child: Column(children: [
ExpansionPanelList(
animationDuration: Duration(seconds: 1),
dividerColor: Colors.white,
children: [
ExpansionPanel(
backgroundColor: Colors.grey[800],
canTapOnHeader: true,
headerBuilder: (context, isExpanded) {
if (isExpanded){
return Row(
children: [
Image.asset('assets/1.png',height: 100,width: 100,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title',style: TextStyle(color: Colors.white),),
Text('By J. K. Rowling',style: TextStyle(color: Colors.white),),
Text(longtext, overflow: TextOverflow.ellipsis, maxLines: _isopen[0] ? 50 : 7,style: TextStyle(color: Colors.white),),
SizedBox(height: 10,),
Text('Size:0.2Mb',style: TextStyle(color: Colors.white),),
Text('Genre:Fantasy Fiction',style: TextStyle(color: Colors.white),),
],),
],);
}else{
return Row(children: [
Image.asset('assets/1.png',height: 100,width: 100,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title',style: TextStyle(color: Colors.white),),
Text('By J. K. Rowling',style: TextStyle(color: Colors.white),),
Text(longtext, overflow: TextOverflow.ellipsis, maxLines: _isopen[0] ? 50 : 7,style: TextStyle(color: Colors.white),),
SizedBox(height: 10,),
Text('Size:0.2Mb',style: TextStyle(color: Colors.white),),
Text('Genre:Fantasy Fiction',style: TextStyle(color: Colors.white),),
],),
],);
}
}, body: Text(""),isExpanded: _isopen[0]),
],
expansionCallback: (panelIndex, isExpanded) => setState((){
_isopen[panelIndex]= !isExpanded;
}),
),
],),),
),
Output
This code when expanded the text completely fits the container.
Container(
child: Column(
children: [
Row(children: [
Image.asset('assets/1.png',height: 150,width: 150,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AnimatedContainer(
curve: Curves.easeOut,
height: (expanded)?(MediaQuery.of(context).size.height*0.45):200,
duration: Duration(milliseconds: 400),
child: InkWell(
onTap: (){
setState(() {
expanded?expanded=false:expanded=true;
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('searchBooksList[index].title'),
Text('By ${'searchBooksList[index].author'}'),
Text('\n${longtext}', overflow: TextOverflow.ellipsis, maxLines: expanded ? 50 : 7,
),
SizedBox(height: 10,),
Text("Size:0.2Mb"),
Text("Genre:Adventure"),
],
),
),
),
],
),
),
],),
],
))
Gif
Disclaimer:
While expanding it will produce A RenderFlex overflowed error
Don't give height for container just put container in Expanded widget
for example :
Expanded(
child: container(
child: Text(
"Put your Text Here",
)
)
)