Reputation: 303
I created a custom ListTile which should have two score centered in the middle and information on the left and right of this (screenshot).
The information on the left can have arbitrary length and should use TextOverflow.ellipsis when it's too long. I cannot get this to work since the Text does not seem to know the width it is supposed to have and overflows. I have tried wrapping the Text widgets into SizedBox, Expanded, etc. This has not worked.
flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following message was thrown during layout:
flutter: A RenderFlex overflowed by 15 pixels on the right.
flutter:
flutter: The overflowing RenderFlex has an orientation of Axis.horizontal.
flutter: The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and
flutter: black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
flutter: Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the
flutter: RenderFlex to fit within the available space instead of being sized to their natural size.
flutter: This is considered an error condition because it indicates that there is content that cannot be
flutter: seen. If the content is legitimately bigger than the available space, consider clipping it with a
flutter: ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex,
flutter: like a ListView.
flutter: The specific RenderFlex in question is:
flutter: RenderFlex#c64e4 relayoutBoundary=up11 OVERFLOWING
flutter: creator: Row ← Expanded ← Row ← Column ← ConstrainedBox ← Container ← Listener ← _GestureSemantics
flutter: ← RawGestureDetector ← GestureDetector ← InkWell ← ScopedModelDescendant<BaseballModel> ← ⋯
flutter: parentData: offset=Offset(0.0, 0.0); flex=1; fit=FlexFit.tight (can use size)
flutter: constraints: BoxConstraints(w=143.0, 0.0<=h<=Infinity)
flutter: size: Size(143.0, 70.0)
flutter: direction: horizontal
flutter: mainAxisAlignment: start
flutter: mainAxisSize: max
flutter: crossAxisAlignment: center
flutter: textDirection: ltr
flutter: verticalDirection: down
flutter: ◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
My Code is the following:
@immutable
class GameTile extends StatelessWidget {
final Game game;
Color highligtColor = Colors.red;
GameTile({this.game});
@override
Widget build(BuildContext context) {
return InkWell(
child: Container(
height: 70.0,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Container(
width: 8.0,
height: 70.0,
color: highligtColor,
),
Padding(
padding: EdgeInsets.only(left: 15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
game.awayTeam.name,
overflow: TextOverflow.ellipsis,
),
Text(
game.homeTeam.name,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Column(
children: [
Text(
game.awayRuns,
style: TextStyle(fontWeight: FontWeight.w900),
),
Text(
game.homeRuns,
style: TextStyle(fontWeight: FontWeight.w900),
),
],
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(game.getFormattedDate()),
Text(game.getFormattedTime()),
]),
Padding(
padding: EdgeInsets.only(left: 8.0, right: 10.0),
child: Container(),
)
],
),
)
],
)
],
),
),
);
}
}
Upvotes: 21
Views: 63760
Reputation: 805
[UPDATE 2023] Add Flexible
so that the child element can stretch to fit the remaining space on the screen without causing a width error.
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: CustomHomeServices(
iconUrl: 'assets/ic_topup.png',
title: 'Deposit \n',
onTap: () {
Navigator.pushNamed(
context,
'/topup',
arguments: cardInfo,
);
},
),
),
// Other children
],
),
Upvotes: 0
Reputation: 4291
In my case, I had lottie view as a child of ROW and I had put wrong path of lottie asset. and I was getting renderflow error and lottie asset error was not showing at the bottom. Fixed lottie assets and this got automatically resolved.
Upvotes: 0
Reputation: 28060
Flexible
or Expanded
SolutionInside a Row
, a Text
widget will never line-wrap nor show ellipses when not inside an Expanded
or Flexible
widget (or another widget which constrains width).
When Flutter performs layout for Row
or Column
, any non-flex factor widgets get laid out in unbounded space. i.e. without any constraints. (Flexible
, Expanded
and Spacer
are the only flex-factor widgets.)
So when Text
is being laid out inside the Row
, it will never be so wide as to hit a width constraint and get wrapped because...
... there are no constraints during Row
layout for non-flex factor widgets.
Placing the Text
widget inside a Flexible
or Expanded
will cause Flutter to calculate remaining space during Row
layout and impose that constraint. This will cause wrapping if needed & ellipses if specified: Text("blahblah", overflow: TextOverflow.ellipsis)
.
More details in a related RenderFlex overflowed question.
import 'package:flutter/material.dart';
class FlexTextWrapPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flex Text Wrap'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
width: 400,
child: Row(
children: [
MySpacer(width: 100),
Text("This should easily wrap, but doesn't because I'm in INFINITE SPACE"),
MySpacer(width: 100),
],
),
),
SizedBox(
width: 400,
child: Row(
children: [
MySpacer(width: 100),
Expanded(child: Text("This should easily wrap, and DOES because I'm in BOUNDED SPACE")),
MySpacer(width: 100),
],
),
),
SizedBox(
width: 400,
child: Row(
children: [
MySpacer(width: 100),
Expanded(
child: Text("This should easily wrap, and DOES because I'm in BOUNDED SPACE",
overflow: TextOverflow.ellipsis, // default is .clip
maxLines: 2,),// default is 1
),
MySpacer(width: 100),
],
),
),
],
),
);
}
}
class MySpacer extends StatelessWidget {
final double width;
MySpacer({this.width});
@override
Widget build(BuildContext context) {
return Container(child: SizedBox(width: width, height: 16,), color: Colors.lightBlueAccent,);
}
}
Upvotes: 15
Reputation: 4436
If you want the child content to just fit the content without being expanded. You must use Flexible
in combination with MainAxisSize.min
inside Row:
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 2),
child: Text("abc",
style: TextStyle(
color: Colors.white,
fontSize: 13),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
Icon(Icons.arrow_drop_down, size: 10, color: Colors.white,)
],
)
Upvotes: 8
Reputation: 22404
Just wrap the overflowed widget with Flexible
new Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Checkbox(
onChanged: (bool){},
),
Flexible(
child: new Text(
"This text can be so loooooooooooooong",
),
),
],
),
Upvotes: 53
Reputation: 9589
I ran your code on my phone and an exception occurred only after meddling with the teams names and the width of the widget.
I think this problem arises because your code doesn't adapt to different display sizes well enough, especially if the team names have a different length:
I created a modified widget that adapts well to constraint changes and uses the available space in a more clever way. I did this by flattening your nested Row
s and Column
s as far as possible, resulting in a more shallow, more flexible widget tree:
return InkWell(
child: Container(
height: 70.0,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(width: 8.0, height: 70.0, color: highlightColor),
SizedBox(width: 15.0),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(game.awayTeam.name, overflow: TextOverflow.ellipsis),
Text(game.homeTeam.name, overflow: TextOverflow.ellipsis),
],
),
Spacer(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(game.awayRuns, style: TextStyle(fontWeight: FontWeight.w900)),
Text(game.homeRuns, style: TextStyle(fontWeight: FontWeight.w900)),
],
),
Spacer(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(game.getFormattedDate()),
Text(game.getFormattedTime()),
]
),
SizedBox(width: 18.0),
],
),
),
);
Most of the time, it's better to use just a few widgets in a shallow tree. Nesting all kinds of "organizational" widgets, especially Column
s, Row
s and Expanded
s often creates situations where an Expanded
always requests the same size (or ratio of the parent size) without even considering the dimensions of its content.
That can lead to content overflowing, while there is unused negative space at other parts of the widget.
Upvotes: 6