Baseline Aligned Row (#30746)
Text in a baseline aligned row now works, and the height of the row is properly calculated.
diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart
index 3208563..d34d84f 100644
--- a/packages/flutter/lib/src/material/input_decorator.dart
+++ b/packages/flutter/lib/src/material/input_decorator.dart
@@ -1058,8 +1058,7 @@
@override
double computeDistanceToActualBaseline(TextBaseline baseline) {
- assert(false, 'not implemented');
- return 0.0;
+ return _boxParentData(input).offset.dy + input.computeDistanceToActualBaseline(baseline);
}
// Records where the label was painted.
diff --git a/packages/flutter/lib/src/rendering/flex.dart b/packages/flutter/lib/src/rendering/flex.dart
index 908d0a4..3208df7 100644
--- a/packages/flutter/lib/src/rendering/flex.dart
+++ b/packages/flutter/lib/src/rendering/flex.dart
@@ -508,7 +508,6 @@
// Intrinsic cross size is the max of the intrinsic cross sizes of the
// children, after the flexible children are fit into the available space,
// with the children sized using their max intrinsic dimensions.
- // TODO(ianh): Support baseline alignment.
// Get inflexible space using the max intrinsic dimensions of fixed children in the main direction.
final double availableMainSpace = extent;
@@ -750,6 +749,8 @@
if (totalFlex > 0 || crossAxisAlignment == CrossAxisAlignment.baseline) {
final double spacePerFlex = canFlex && totalFlex > 0 ? (freeSpace / totalFlex) : double.nan;
child = firstChild;
+ double maxSizeAboveBaseline = 0;
+ double maxSizeBelowBaseline = 0;
while (child != null) {
final int flex = _getFlex(child);
if (flex > 0) {
@@ -809,8 +810,18 @@
return true;
}());
final double distance = child.getDistanceToBaseline(textBaseline, onlyReal: true);
- if (distance != null)
+ if (distance != null) {
maxBaselineDistance = math.max(maxBaselineDistance, distance);
+ maxSizeAboveBaseline = math.max(
+ distance,
+ maxSizeAboveBaseline,
+ );
+ maxSizeBelowBaseline = math.max(
+ child.size.height - distance,
+ maxSizeBelowBaseline,
+ );
+ crossSize = maxSizeAboveBaseline + maxSizeBelowBaseline;
+ }
}
final FlexParentData childParentData = child.parentData;
child = childParentData.nextSibling;
diff --git a/packages/flutter/test/widgets/basic_test.dart b/packages/flutter/test/widgets/basic_test.dart
index a1d6b91..41e218c 100644
--- a/packages/flutter/test/widgets/basic_test.dart
+++ b/packages/flutter/test/widgets/basic_test.dart
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:math' as math;
import 'package:flutter_test/flutter_test.dart';
+import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
@@ -146,6 +148,64 @@
});
});
+ group('Row', () {
+ testWidgets('multiple baseline aligned children', (WidgetTester tester) async {
+ final UniqueKey key1 = UniqueKey();
+ final UniqueKey key2 = UniqueKey();
+ const double fontSize1 = 54;
+ const double fontSize2 = 14;
+
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Scaffold(
+ body: Container(
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.baseline,
+ textBaseline: TextBaseline.alphabetic,
+ children: <Widget>[
+ Text('big text',
+ key: key1,
+ style: const TextStyle(fontSize: fontSize1),
+ ),
+ Text('one\ntwo\nthree\nfour\nfive\nsix\nseven',
+ key: key2,
+ style: const TextStyle(fontSize: fontSize2)
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+
+ final RenderBox textBox1 = tester.renderObject(find.byKey(key1));
+ final RenderBox textBox2 = tester.renderObject(find.byKey(key2));
+ final RenderBox rowBox = tester.renderObject(find.byType(Row));
+
+ // The two Texts are baseline aligned, so some portion of them extends
+ // both above and below the baseline. The first has a huge font size, so
+ // it extends higher above the baseline than usual. The second has many
+ // lines, but being aligned by the first line's baseline, they hang far
+ // below the baseline. The size of the parent row is just enough to
+ // contain both of them.
+ const double ahemBaselineLocation = 0.8; // https://web-platform-tests.org/writing-tests/ahem.html
+ const double aboveBaseline1 = fontSize1 * ahemBaselineLocation;
+ const double belowBaseline1 = fontSize1 * (1 - ahemBaselineLocation);
+ const double aboveBaseline2 = fontSize2 * ahemBaselineLocation;
+ const double belowBaseline2 = fontSize2 * (1 - ahemBaselineLocation) + fontSize2 * 6;
+ final double aboveBaseline = math.max(aboveBaseline1, aboveBaseline2);
+ final double belowBaseline = math.max(belowBaseline1, belowBaseline2);
+ expect(rowBox.size.height, greaterThan(textBox1.size.height));
+ expect(rowBox.size.height, greaterThan(textBox2.size.height));
+ expect(rowBox.size.height, closeTo(aboveBaseline + belowBaseline, .001));
+ expect(tester.getTopLeft(find.byKey(key1)).dy, 0);
+ expect(
+ tester.getTopLeft(find.byKey(key2)).dy,
+ closeTo(aboveBaseline1 - aboveBaseline2, .001),
+ );
+ });
+ });
+
test('UnconstrainedBox toString', () {
expect(
const UnconstrainedBox(constrainedAxis: Axis.vertical,).toString(),