From c825fb196306c488daecae0073651ac7465edf58 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Tue, 20 Sep 2022 14:45:08 -0700 Subject: [PATCH] Fix `InputDecorator` child vertical alignment (#112003) --- .../lib/src/material/input_decorator.dart | 17 ++++--- .../test/material/input_decorator_test.dart | 48 +++++++++++++++++++ 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 7df5b694187..d9f118e535d 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -1114,15 +1114,13 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin + topHeight + inputInternalBaseline + baselineAdjustment - + interactiveAdjustment; - final double maxContentHeight = containerHeight - - contentPadding.top - - topHeight - - contentPadding.bottom; + + interactiveAdjustment + + densityOffset.dy / 2.0; + final double maxContentHeight = containerHeight - contentPadding.vertical - topHeight - densityOffset.dy; final double alignableHeight = fixAboveInput + inputHeight + fixBelowInput; final double maxVerticalOffset = maxContentHeight - alignableHeight; final double textAlignVerticalOffset = maxVerticalOffset * textAlignVerticalFactor; - final double inputBaseline = topInputBaseline + textAlignVerticalOffset + densityOffset.dy / 2.0; + final double inputBaseline = topInputBaseline + textAlignVerticalOffset; // The three main alignments for the baseline when an outline is present are // @@ -1302,7 +1300,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin @override double computeDistanceToActualBaseline(TextBaseline baseline) { - return _boxParentData(input!).offset.dy + input!.computeDistanceToActualBaseline(baseline)!; + return _boxParentData(input!).offset.dy + (input?.computeDistanceToActualBaseline(baseline) ?? 0.0); } // Records where the label was painted. @@ -1325,12 +1323,13 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin final double overallWidth = constraints.maxWidth; final double overallHeight = layout.containerHeight + layout.subtextHeight; + final RenderBox? container = this.container; if (container != null) { final BoxConstraints containerConstraints = BoxConstraints.tightFor( height: layout.containerHeight, width: overallWidth - _boxSize(icon).width, ); - container!.layout(containerConstraints, parentUsesSize: true); + container.layout(containerConstraints, parentUsesSize: true); final double x; switch (textDirection) { case TextDirection.rtl: @@ -1340,7 +1339,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin x = _boxSize(icon).width; break; } - _boxParentData(container!).offset = Offset(x, 0.0); + _boxParentData(container).offset = Offset(x, 0.0); } late double height; diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index ac6fed3fce4..90edae922dd 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -2290,6 +2290,54 @@ void main() { // In between the center and bottom aligned cases. expect(tester.getTopLeft(find.text(text)).dy, moreOrLessEquals(useMaterial3 ? 497.9375 : 498.5, epsilon: .0001)); }); + + testWidgets('works with density and content padding', (WidgetTester tester) async { + const Key key = Key('child'); + const Key containerKey = Key('container'); + const double totalHeight = 100.0; + const double childHeight = 20.0; + const VisualDensity visualDensity = VisualDensity(vertical: VisualDensity.maximumDensity); + const EdgeInsets contentPadding = EdgeInsets.only(top: 6, bottom: 14); + + await tester.pumpWidget( + Center( + child: SizedBox( + key: containerKey, + height: totalHeight, + child: buildInputDecorator( + useMaterial3: useMaterial3, + // isEmpty: false (default) + // isFocused: false (default) + expands: true, + decoration: const InputDecoration( + border: InputBorder.none, + contentPadding: contentPadding, + ), + textAlignVertical: TextAlignVertical.center, + visualDensity: visualDensity, + child: const SizedBox(key: key, height: childHeight), + ), + ), + ), + ); + + // Vertical components: contentPadding.vertical, densityOffset.y, child + final double childVerticalSpaceAffordance = totalHeight + - visualDensity.baseSizeAdjustment.dy + - contentPadding.vertical; + + // TextAlignVertical.center is specified so `child` needs to be centered + // in the avaiable space. + final double childMargin = (childVerticalSpaceAffordance - childHeight) / 2; + final double childTop = visualDensity.baseSizeAdjustment.dy / 2.0 + + contentPadding.top + + childMargin; + + expect( + tester.getTopLeft(find.byKey(key)).dy, + tester.getTopLeft(find.byKey(containerKey)).dy + childTop, + ); + }); }); group('outline border', () {