David PHAM-VAN

Implement custom table widths

@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 ## 1.3.27 3 ## 1.3.27
4 4
5 - Add Roll Paper support 5 - Add Roll Paper support
  6 +- Implement custom table widths
6 7
7 ## 1.3.26 8 ## 1.3.26
8 9
@@ -86,14 +86,91 @@ class _TableContext extends WidgetContext { @@ -86,14 +86,91 @@ class _TableContext extends WidgetContext {
86 int lastLine = 0; 86 int lastLine = 0;
87 } 87 }
88 88
  89 +class _ColumnLayout {
  90 + _ColumnLayout(this.width, this.flex);
  91 +
  92 + final double width;
  93 + final double flex;
  94 +}
  95 +
  96 +abstract class TableColumnWidth {
  97 + const TableColumnWidth();
  98 +
  99 + _ColumnLayout layout(
  100 + Widget child, Context context, BoxConstraints constraints);
  101 +}
  102 +
  103 +class IntrinsicColumnWidth extends TableColumnWidth {
  104 + const IntrinsicColumnWidth({this.flex});
  105 +
  106 + final double flex;
  107 +
  108 + @override
  109 + _ColumnLayout layout(
  110 + Widget child, Context context, BoxConstraints constraints) {
  111 + if (flex != null) {
  112 + return _ColumnLayout(0, flex);
  113 + }
  114 +
  115 + child.layout(context, const BoxConstraints());
  116 + assert(child.box != null);
  117 + final double calculatedWidth =
  118 + child.box.width == double.infinity ? 0 : child.box.width;
  119 + final double childFlex = flex ??
  120 + (child is Expanded
  121 + ? child.flex.toDouble()
  122 + : (child.box.width == double.infinity ? 1 : 0));
  123 + return _ColumnLayout(calculatedWidth, childFlex);
  124 + }
  125 +}
  126 +
  127 +class FixedColumnWidth extends TableColumnWidth {
  128 + const FixedColumnWidth(this.width) : assert(width != null);
  129 +
  130 + final double width;
  131 +
  132 + @override
  133 + _ColumnLayout layout(
  134 + Widget child, Context context, BoxConstraints constraints) {
  135 + return _ColumnLayout(width, 0);
  136 + }
  137 +}
  138 +
  139 +class FlexColumnWidth extends TableColumnWidth {
  140 + const FlexColumnWidth([this.flex = 1.0]) : assert(flex != null);
  141 +
  142 + final double flex;
  143 +
  144 + @override
  145 + _ColumnLayout layout(
  146 + Widget child, Context context, BoxConstraints constraints) {
  147 + return _ColumnLayout(0, flex);
  148 + }
  149 +}
  150 +
  151 +class FractionColumnWidth extends TableColumnWidth {
  152 + const FractionColumnWidth(this.value);
  153 +
  154 + final double value;
  155 +
  156 + @override
  157 + _ColumnLayout layout(
  158 + Widget child, Context context, BoxConstraints constraints) {
  159 + return _ColumnLayout(constraints.maxWidth * value, 0);
  160 + }
  161 +}
  162 +
89 /// A widget that uses the table layout algorithm for its children. 163 /// A widget that uses the table layout algorithm for its children.
90 class Table extends Widget implements SpanningWidget { 164 class Table extends Widget implements SpanningWidget {
91 Table( 165 Table(
92 {this.children = const <TableRow>[], 166 {this.children = const <TableRow>[],
93 this.border, 167 this.border,
94 this.defaultVerticalAlignment = TableCellVerticalAlignment.top, 168 this.defaultVerticalAlignment = TableCellVerticalAlignment.top,
  169 + this.columnWidths,
  170 + this.defaultColumnWidth = const IntrinsicColumnWidth(),
95 this.tableWidth = TableWidth.max}) 171 this.tableWidth = TableWidth.max})
96 : assert(children != null), 172 : assert(children != null),
  173 + assert(defaultColumnWidth != null),
97 super(); 174 super();
98 175
99 factory Table.fromTextArray( 176 factory Table.fromTextArray(
@@ -140,6 +217,9 @@ class Table extends Widget implements SpanningWidget { @@ -140,6 +217,9 @@ class Table extends Widget implements SpanningWidget {
140 217
141 _TableContext _context = _TableContext(); 218 _TableContext _context = _TableContext();
142 219
  220 + final TableColumnWidth defaultColumnWidth;
  221 + final Map<int, TableColumnWidth> columnWidths;
  222 +
143 @override 223 @override
144 WidgetContext saveContext() { 224 WidgetContext saveContext() {
145 return _context; 225 return _context;
@@ -163,21 +243,20 @@ class Table extends Widget implements SpanningWidget { @@ -163,21 +243,20 @@ class Table extends Widget implements SpanningWidget {
163 for (TableRow row in children) { 243 for (TableRow row in children) {
164 int n = 0; 244 int n = 0;
165 for (Widget child in row.children) { 245 for (Widget child in row.children) {
166 - child.layout(context, const BoxConstraints());  
167 - assert(child.box != null);  
168 - final double calculatedWidth =  
169 - child.box.width == double.infinity ? 0.0 : child.box.width;  
170 - final double childFlex = child is Expanded  
171 - ? child.flex.toDouble()  
172 - : (child.box.width == double.infinity ? 1.0 : 0.0); 246 + final TableColumnWidth columnWidth =
  247 + columnWidths != null && columnWidths[n] != null
  248 + ? columnWidths[n]
  249 + : defaultColumnWidth;
  250 + final _ColumnLayout columnLayout =
  251 + columnWidth.layout(child, context, constraints);
173 if (flex.length < n + 1) { 252 if (flex.length < n + 1) {
174 - flex.add(childFlex);  
175 - _widths.add(calculatedWidth); 253 + flex.add(columnLayout.flex);
  254 + _widths.add(columnLayout.width);
176 } else { 255 } else {
177 - if (childFlex > 0) {  
178 - flex[n] *= childFlex; 256 + if (columnLayout.flex > 0) {
  257 + flex[n] = math.max(flex[n], columnLayout.flex);
179 } 258 }
180 - _widths[n] = math.max(_widths[n], calculatedWidth); 259 + _widths[n] = math.max(_widths[n], columnLayout.width);
181 } 260 }
182 n++; 261 n++;
183 } 262 }
@@ -131,6 +131,20 @@ void main() { @@ -131,6 +131,20 @@ void main() {
131 ])); 131 ]));
132 }); 132 });
133 133
  134 + test('Table Widget Widths', () {
  135 + pdf.addPage(Page(
  136 + build: (Context context) => Table(
  137 + children: buildTable(context: context, count: 20),
  138 + border: const TableBorder(),
  139 + columnWidths: <int, TableColumnWidth>{
  140 + 0: const FixedColumnWidth(80),
  141 + 1: const FlexColumnWidth(2),
  142 + 2: const FractionColumnWidth(.2),
  143 + },
  144 + ),
  145 + ));
  146 + });
  147 +
134 tearDownAll(() { 148 tearDownAll(() {
135 final File file = File('widgets-table.pdf'); 149 final File file = File('widgets-table.pdf');
136 file.writeAsBytesSync(pdf.save()); 150 file.writeAsBytesSync(pdf.save());