Skip to content

Commit 829e44d

Browse files
authored
Fixed label alignment (#115409)
Co-authored-by: Qun Cheng <[email protected]>
1 parent 55927d8 commit 829e44d

File tree

2 files changed

+60
-11
lines changed

2 files changed

+60
-11
lines changed

packages/flutter/lib/src/material/input_decorator.dart

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
703703
required TextBaseline textBaseline,
704704
required bool isFocused,
705705
required bool expands,
706+
required bool material3,
706707
TextAlignVertical? textAlignVertical,
707708
}) : assert(decoration != null),
708709
assert(textDirection != null),
@@ -713,7 +714,8 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
713714
_textBaseline = textBaseline,
714715
_textAlignVertical = textAlignVertical,
715716
_isFocused = isFocused,
716-
_expands = expands;
717+
_expands = expands,
718+
_material3 = material3;
717719

718720
static const double subtextGap = 8.0;
719721

@@ -831,6 +833,16 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
831833
markNeedsLayout();
832834
}
833835

836+
bool get material3 => _material3;
837+
bool _material3 = false;
838+
set material3(bool value) {
839+
if (_material3 == value) {
840+
return;
841+
}
842+
_material3 = value;
843+
markNeedsLayout();
844+
}
845+
834846
// Indicates that the decoration should be aligned to accommodate an outline
835847
// border.
836848
bool get _isOutlineAligned {
@@ -1473,18 +1485,26 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
14731485
// _BorderContainer's x and is independent of label's x.
14741486
switch (textDirection) {
14751487
case TextDirection.rtl:
1476-
decoration.borderGap.start = lerpDouble(labelX + _boxSize(label).width,
1477-
_boxSize(container).width / 2.0 + floatWidth / 2.0,
1478-
floatAlign);
1488+
double offsetToPrefixIcon = 0.0;
1489+
if (prefixIcon != null && !decoration.alignLabelWithHint) {
1490+
offsetToPrefixIcon = material3 ? _boxSize(prefixIcon).width - left : 0;
1491+
}
1492+
decoration.borderGap.start = lerpDouble(labelX + _boxSize(label).width + offsetToPrefixIcon,
1493+
_boxSize(container).width / 2.0 + floatWidth / 2.0,
1494+
floatAlign);
14791495

14801496
break;
14811497
case TextDirection.ltr:
14821498
// The value of _InputBorderGap.start is relative to the origin of the
14831499
// _BorderContainer which is inset by the icon's width. Although, when
14841500
// floating label is centered, it's already relative to _BorderContainer.
1485-
decoration.borderGap.start = lerpDouble(labelX - _boxSize(icon).width,
1486-
_boxSize(container).width / 2.0 - floatWidth / 2.0,
1487-
floatAlign);
1501+
double offsetToPrefixIcon = 0.0;
1502+
if (prefixIcon != null && !decoration.alignLabelWithHint) {
1503+
offsetToPrefixIcon = material3 ? (-_boxSize(prefixIcon).width + left) : 0;
1504+
}
1505+
decoration.borderGap.start = lerpDouble(labelX - _boxSize(icon).width + offsetToPrefixIcon,
1506+
_boxSize(container).width / 2.0 - floatWidth / 2.0,
1507+
floatAlign);
14881508
break;
14891509
}
14901510
decoration.borderGap.extent = label!.size.width * _kFinalLabelScale;
@@ -1529,17 +1549,26 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
15291549
final double scale = lerpDouble(1.0, _kFinalLabelScale, t)!;
15301550
final double centeredFloatX = _boxParentData(container!).offset.dx +
15311551
_boxSize(container).width / 2.0 - floatWidth / 2.0;
1532-
final double floatStartX;
1552+
final double startX;
1553+
double floatStartX;
15331554
switch (textDirection) {
15341555
case TextDirection.rtl: // origin is on the right
1535-
floatStartX = labelOffset.dx + labelWidth * (1.0 - scale);
1556+
startX = labelOffset.dx + labelWidth * (1.0 - scale);
1557+
floatStartX = startX;
1558+
if (prefixIcon != null && !decoration.alignLabelWithHint) {
1559+
floatStartX += material3 ? _boxSize(prefixIcon).width - contentPadding.left : 0.0;
1560+
}
15361561
break;
15371562
case TextDirection.ltr: // origin on the left
1538-
floatStartX = labelOffset.dx;
1563+
startX = labelOffset.dx;
1564+
floatStartX = startX;
1565+
if (prefixIcon != null && !decoration.alignLabelWithHint) {
1566+
floatStartX += material3 ? -_boxSize(prefixIcon).width + contentPadding.left : 0.0;
1567+
}
15391568
break;
15401569
}
15411570
final double floatEndX = lerpDouble(floatStartX, centeredFloatX, floatAlign)!;
1542-
final double dx = lerpDouble(floatStartX, floatEndX, t)!;
1571+
final double dx = lerpDouble(startX, floatEndX, t)!;
15431572
final double dy = lerpDouble(0.0, floatingY - labelOffset.dy, t)!;
15441573
_labelTransform = Matrix4.identity()
15451574
..translate(dx, labelOffset.dy + dy)
@@ -1662,6 +1691,7 @@ class _Decorator extends RenderObjectWidget with SlottedMultiChildRenderObjectWi
16621691
textAlignVertical: textAlignVertical,
16631692
isFocused: isFocused,
16641693
expands: expands,
1694+
material3: Theme.of(context).useMaterial3,
16651695
);
16661696
}
16671697

packages/flutter/test/material/input_decorator_test.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,6 +2823,25 @@ void main() {
28232823
expect(getBorderBottom(tester), 120.0);
28242824
expect(getBorderWeight(tester), 1.0);
28252825
});
2826+
2827+
testWidgets('Floating label is aligned with prefixIcon by default in M3', (WidgetTester tester) async {
2828+
await tester.pumpWidget(
2829+
buildInputDecorator(
2830+
useMaterial3: useMaterial3,
2831+
decoration: const InputDecoration(
2832+
prefixIcon: Icon(Icons.ac_unit),
2833+
labelText: 'label',
2834+
border: OutlineInputBorder(),
2835+
),
2836+
isFocused: true,
2837+
),
2838+
);
2839+
2840+
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 56.0));
2841+
expect(tester.getTopLeft(find.text('label')).dx, useMaterial3 ? 12.0 : 48.0);
2842+
expect(tester.getBottomLeft(find.text('text')).dx, 48.0);
2843+
expect(getBorderWeight(tester), 2.0);
2844+
});
28262845
});
28272846

28282847
group('3 point interpolation alignment', () {

0 commit comments

Comments
 (0)