Button within Table within Gridview within Sizedbox or Flex is not clickable dependent on other table rows - Flutter - flutter

I am rendering a standard Table inside a GridView, inside a Flex inside a Row. The 2nd row of the table includes a Button.
When the contents of the first row of the table are above a certain size the clickable region of the button begins to cut off, missing entirely over a certain size.
Note: this is using Flutter Web, I have not tested on Mobile/Desktop.
I have created a minimal reproducible example in an attempt to isolate all logic.
Widget _render() {
return Row(mainAxisSize: MainAxisSize.max, children: [
SizedBox(
width: 900,
height: 900,
child: GridView.count(
crossAxisCount: 2,
children: <Widget>[
Table(border: TableBorder.all(), children: <TableRow>[
TableRow(
children: <Widget>[
TableCell(
child: Text(''),
),
TableCell(
child: SizedBox(
height:
440, //The clickable region of the button begins to be cut off around 430, and stops altogether by 450
))
],
),
TableRow(children: <Widget>[
TableCell(
child: Text(""),
),
TableCell(
child: TextButton(
onPressed: () => {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Hi Button"))),
},
child: Text("Hi"))),
])
]),
],
),
),
]);
}
What is causing this effect? I am assuming it is some interaction between the visible container and the Table.
Edit: as suggested by #pskink rendered with debugPaintSizEnabled flag which highlights the problem perfectly. However; how would you fix?

Related

how to use TabBar view inside scrollable widget in flutter

I have this design, The first section in the red box is fixed height size, and The second section is the dynamic height (ListviewBuilder) which changed the content based on the tabBar.
My question is How can I use the TabBar view inside the scrollable widget (custom scroll view/listview etc..)
the solution That I currently found is to use a customScrollView and use SliverFillRemaining like that
SliverFillRemaining(
child: TabBarView(
children: [],
),
),
but that adds extra white space at the bottom of the list and I can't remove it by
making hasScrollBody property false
You could probably achieve what you want with this kind of template :
Scaffold(
body: Column(
children: [
Container(
height: MediaQuery.of(context).size.height * .33,
child: Container(/* Content of the first section */),
),
Expanded(
child: DefaultTabController(
length: 2,
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Container(
height: 50,
child: TabBar(
tabs: [Text("Guest"), Text("Service")],
),
),
),
SliverFillRemaining(
child: TabBarView(
children: [
// Your ListView Builder here
],
),
),
],
),
),
),
],
),
);
Seeing the bit of code you posted, it is probably close to what you already have but after test it doesn't adds extra white space at the bottom.
If it continue to display the same behavior, adding a little more context could help us provide a more accurate answer.

Make Container fill TableCell in Flutter

I'm trying to make a Table with two cells of the same width and height, so that the height depends on the size of the content. However, the smaller TableCell always shrinks:
This is what I'm trying to implement:
Here's the code:
Table(
children: [
TableRow(
children: [
TableCell(
child: Container(
color: Colors.green,
child: Text(
'long text long text long text long text long text long text long text'),
),
),
TableCell(
child: Container(
color: Colors.orange,
child: Text('short text'),
),
),
],
)
],
),
P.S. I could solve it by adding verticalAlignment: TableCellVerticalAlignment.fill, to the smaller cell, but any cell can be the smaller one, depending on the content. When I add this line to both cells, the whole table disappears. The only bypass I could imagine is to calculate the length of the content and find the smaller cell, but I wonder if there is a way to implement this UI directly with Flutter.
Would appreciate any help.
1. Row with IntrinsicHeight
IntrinsicHeight limits the height of the Row to the content size, which however is considered a 'relatively expensive' approach and is not recommended.
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
color: Colors.green,
child: Text(
'long text long text long text long text long text',
))),
Expanded(
child: Container(
color: Colors.orange,
child: Text(
'short text',
))),
],
),
),
2. Table with TableCellVerticalAlignment.fill
As mentioned in the question, the .fill option must not be used in the largest TableCell, because in this case the TableRow will have zero height. This is the preferred solution, because it doesn't have the 'expensiveness' issue of the previous one.
final texts = ['long text long text long text long text long text', 'short text'];
final colors = [Colors.green, Colors.orange];
// find the longest text and its index
final max = texts.asMap().entries.reduce(
(a, b) => (a.value.length > b.value.length) ? a : b,
);
return Table(children: [
TableRow(
children: texts
.asMap()
.entries
.map((e) => TableCell(
// use .fill in all cells except the largest
verticalAlignment: (e.key != max.key)
? TableCellVerticalAlignment.fill
: TableCellVerticalAlignment.top,
child: Container(
color: colors[e.key],
child: Text(e.value),
)))
.toList(),
),
]);

How to force a ListView not to expand more than other widgets in a row (Flutter)

I'm struggling with this and can't describe it as well as I should on search engine, so here's my problem: I have a Row containing two Expanded with flex: 5 aiming to have two width-equal cells; inside the first cell, I have a Column (containing a Table and a Button); inside the second cell I have a Column (containing a ListView and a Button); I'd like to force the ListView to become scrollable once its content gets higher than first cell's intrinsic height, so second cell's height never gets higher than first cell's height.
Row(
children: [
Expanded(
flex: 5,
child: Column(
children: [
DataTable(),
ElevatedButton()
]
), // Column
), // Expanded
Expanded(
flex: 5,
child: Column(
children: [
ListView(),
ElevatedButton()
]
), // Column
) // Expanded
]
) // Row
I lost myself trying stuff with shrinkWrap: true on the ListView, IntrinsicHeight() around the Row, etc.
Thank you for your help!
EDIT:
Solution I found is going the hard way by listening to first cell's size changes and to set its height as second cell's height (thanks to this Medium link). Even tho I'd rather go for a cleaner way, it seems to work like it should.
This is what my code currently looks like:
Row(
children: [
Expanded(
flex: 5,
child: WidgetSize(
onChange: (size) {
if (size != null)
setState(() => heightOfTable = (size as Size).height);
},
child: Column(
children: [
DataTable(),
ElevatedButton()
]
), // Column
), // WidgetSize
), // Expanded
Expanded(
flex: 5,
child: Container(
height: heightOfTable,
child: Column(
children: [
ListView(),
ElevatedButton()
]
), // Column
), // Container
) // Expanded
]
) // Row
If you've got a better idea, please let me know! :)
I think you can try wrapping the ListView inside a Container and give a suitable height and `width.
Row(
children: [
Expanded(
flex: 5,
child: Column(
children: [
DataTable(),
ElevatedButton()
]
), // Column
), // Expanded
Expanded(
flex: 5,
child: Column(
children: [
Container(
height:,
width:,
child: ListView()),
ElevatedButton()
]
), // Column
) // Expanded
]
) // Row

Fix minimum width to a Widget which needs to expand in Flutter

I need to fix a minimum width to my Column Widgets. Inside each of them, I have Text Widgets which can be very short or very long. I need to fix a minimum width to them in order to have an acceptable size of Column even if the text is short. The other Column need obviously to adapt himself.
Row(children: [
Column(
children: [
Container(
constraints: BoxConstraints(minWidth: 80), // do not work
child: Text("short text"),
),
],
),
Column(
children: [
Container(
constraints: BoxConstraints(minWidth: 110), // do not work
child: RichText(
text: TextSpan(
text:"very very longggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg text")),
),
],
),
],
)
There's probably a dozen ways to do what you want. And likely none of them straightforward or easy to understand. (The subject of constraints & sizes is quite complicated. See this constraints page for more examples & explanations.)
Here's one potential solution.
This will set a minimum width for the blue column (based on stepWidth), but will expand/grow if the text (child) inside wants to.
The yellow column will resize to accommodate the blue column.
class ExpandedRowPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Expanded Row Page'),
),
body: SafeArea(
child: Center(
child: Row(
children: [
IntrinsicWidth(
stepWidth: 100,
// BLUE Column
child: Container(
color: Colors.lightBlueAccent,
child: Column(
children: [
//Text('Short'),
Text('shrt')
],
)
),
),
// YELLOW Column
Flexible(
child: Container(
alignment: Alignment.center,
color: Colors.yellow,
child: Column(
children: [
Text('Very lonnnnnnnnnnnnnnnnnnnnnnnnnnnng texttttttttttttt'),
],
)
),
)
],
)
),
),
);
}
}
You could do the above without a Flexible yellow column, but a very long text child would cause an Overflow warning without a Flexible or Expanded wrapping widget.
A Row widget by itself has an infinite width constraint. So if a child wants to be bigger than screen width, it can, and will cause an overflow. (Try removing Flexible above and rebuild to see.)
Flexible and Expanded, used only inside Row & Column (or Flex, their superclass), checks screen width and other widgets inside a Row, and provides its children with a defined constraint size instead of infinite. Children (inside Flexible/Expanded) can now look up to parent for a constraint and size themselves accordingly.
A Text widget for example, will wrap its text when it's too wide for constraints given by Flexible/Expanded.
use FittedBox();
suppose Example:
Row(
children: [
Column(
children: [
Container(
constraints: BoxConstraints(minWidth: 80), // do not work
child: Text("short text"),
),
],
),
Column(
children: [
Container(
constraints: BoxConstraints(minWidth: 110), // do not work
child:
FittedBox(
child: RichText(
text: TextSpan(
text:
"very very longggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg text")),
),
),
],
),
],
);

How can I fill whole free place in a column with a children widget with required size property?

I have an UI in Flutter that has a simple circular chart with some text.
This circular chart (https://pub.dev/packages/flutter_circular_chart) has a required size property. So, we must define its size, but in this way it won't be responsive for all UI screen sizes, it does not fit the whole space I'd like to.
So, e.g. I'd like to set its size to also cover the space annotated with blue:
Is it possible to set its size dynamically to fit whole free space in the column?
I tried expaned, fittedbox with double.infinity size parames etc. but neither of them helped.
My code:
Widget _buildChart() {
return Expanded(
child: Container(
color: Colors.green,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
AnimatedCircularChart(
duration: Duration(milliseconds: 0),
key: _chartKey,
size: const Size(140.0, 140.0),
chartType: CircularChartType.Radial,
percentageValues: true,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildText(
'${AppLocalizations.of(context).localize("free")}: $freeCount',
Colors.white),
_buildText(
'${AppLocalizations.of(context).localize("busy")}: $busyCount',
Theme.of(context).buttonColor),
],
)
],
),
),
);
}
Would you be so kind to help me to solve this? How can I make its size responsive? Is it possible at all?
Wrap your AnimatedCircularChart in FittedBox which is further wrapped in Expanded and you don't have to deal with Size anymore. No matter what size you provide, it will always give you the maximum space left.
Expanded( // add this
child: FittedBox( // and add this
child: AnimatedCircularChart(
key: Key("chart_key"),
duration: Duration(milliseconds: 0),
size: Size(1, 1), // no matter even if it is 1, it will take up all remaining space
chartType: CircularChartType.Radial,
percentageValues: true,
initialChartData: data,
),
),
)
Full code:
Widget _buildChart() {
return Expanded(
child: Container(
color: Colors.green,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded( // add this
child: FittedBox( // and add this
child: AnimatedCircularChart(
key: Key("chart_key"),
duration: Duration(milliseconds: 0),
size: Size(1, 1), // no matter even if it is 1, it will take up all remaining space
chartType: CircularChartType.Radial,
percentageValues: true,
initialChartData: data,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text("Free: 14"),
Text("Busy: 31"),
],
)
],
),
),
);
}
Update:
If you are talking about the remaining space above the ring on bigger screen, then it is because of the ring ability to remain circular in shape, so it can't really go beyond that. I have created a small video recording to show you the effect. And I have used size: 1.
Use the LayoutBuilder class for that.
The layoutbuilder class allows you to give a defined height depending on the parent widget constraints. For example you could say that the chart height is 40% of the available height of the parant widget.
For further responsiveness (screen rotation etc.) check out MediaQuery