Fix filled text field active indicator overflows container bounds (#146637)

## Description

This PRs fixes the active indicator vertical position for a filled text field.
Before this PR, the active indicator overflowed of container bounds, After this PR the active indicator is painted inside the container bounds.

Screenshot of filled text field with active indicator width sets to 4.0dp:

| Before | After |
|--------|--------|
| ![image](https://github.com/flutter/flutter/assets/840911/ed2878ba-130a-4410-b170-423d00a8893d) | ![image](https://github.com/flutter/flutter/assets/840911/f78d06c0-a161-4ab6-b01f-dae297939956) | 

</details> 

## Related Issue

Fixes https://github.com/flutter/flutter/issues/146507

## Tests

Adds 1 tests, updates 3 tests.
This commit is contained in:
Bruno Leroux 2024-04-15 09:28:19 +02:00 committed by GitHub
parent 1002ce4b03
commit 63634c25ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 74 additions and 57 deletions

View File

@ -254,15 +254,15 @@ class UnderlineInputBorder extends InputBorder {
bottomRight: borderRadius.bottomRight.clamp(maximum: Radius.circular(rect.height / 2)),
);
// We set the strokeAlign to center, so the behavior is consistent with
// drawLine and with the historical behavior of this border.
BoxBorder.paintNonUniformBorder(canvas, rect,
textDirection: textDirection,
borderRadius: updatedBorderRadius,
bottom: borderSide.copyWith(strokeAlign: BorderSide.strokeAlignCenter),
color: borderSide.color);
textDirection: textDirection,
borderRadius: updatedBorderRadius,
bottom: borderSide.copyWith(strokeAlign: BorderSide.strokeAlignInside),
color: borderSide.color,
);
} else {
canvas.drawLine(rect.bottomLeft, rect.bottomRight, borderSide.toPaint());
final Offset alignInsideOffset = Offset(0, borderSide.width / 2);
canvas.drawLine(rect.bottomLeft - alignInsideOffset, rect.bottomRight - alignInsideOffset, borderSide.toPaint());
}
}

View File

@ -1537,17 +1537,70 @@ void main() {
// Fill is the border's outer path, a rounded rectangle.
expect(box, paints
..drrect(
style: PaintingStyle.fill,
inner: RRect.fromLTRBAndCorners(0.0, 0.0, 800.0, 47.5,
bottomRight: const Radius.elliptical(12.0, 11.5),
bottomLeft: const Radius.elliptical(12.0, 11.5)),
outer: RRect.fromLTRBAndCorners(0.0, 0.0, 800.0, 48.5,
bottomRight: const Radius.elliptical(12.0, 12.5),
bottomLeft: const Radius.elliptical(12.0, 12.5)),
..drrect(
style: PaintingStyle.fill,
inner: RRect.fromLTRBAndCorners(0.0, 0.0, 800.0, 47.0,
bottomRight: const Radius.elliptical(12.0, 11.0),
bottomLeft: const Radius.elliptical(12.0, 11.0)),
outer: RRect.fromLTRBAndCorners(0.0, 0.0, 800.0, 48.0,
bottomRight: const Radius.elliptical(12.0, 12.0),
bottomLeft: const Radius.elliptical(12.0, 12.0)),
));
});
testWidgets('UnderlineInputBorder clips top border to prevent anti-aliasing glitches', (WidgetTester tester) async {
const Rect canvasRect = Rect.fromLTWH(0, 0, 100, 100);
const UnderlineInputBorder border = UnderlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
);
expect(
(Canvas canvas) => border.paint(canvas, canvasRect),
paints
..drrect(
outer: RRect.fromLTRBAndCorners(0.0, 0.0, 100.0, 100.0,
bottomRight: const Radius.elliptical(12.0, 12.0),
bottomLeft: const Radius.elliptical(12.0, 12.0)),
inner: RRect.fromLTRBAndCorners(0.0, 0.0, 100.0, 99.0,
bottomRight: const Radius.elliptical(12.0, 11.0),
bottomLeft: const Radius.elliptical(12.0, 11.0)),
),
);
const UnderlineInputBorder border2 = UnderlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(60.0)),
);
expect(
(Canvas canvas) => border2.paint(canvas, canvasRect),
paints
..drrect(
outer: RRect.fromLTRBAndCorners(0.0, 0.0, 100.0, 100.0,
bottomRight: const Radius.elliptical(50.0, 50.0),
bottomLeft: const Radius.elliptical(50.0, 50.0)),
inner: RRect.fromLTRBAndCorners(0.0, 0.0, 100.0, 99.0,
bottomRight: const Radius.elliptical(50.0, 49.0),
bottomLeft: const Radius.elliptical(50.0, 49.0)),
),
reason: 'clamp is expected',
);
});
testWidgets('UnderlineInputBorder draws bottom border inside container bounds', (WidgetTester tester) async {
const Rect canvasRect = Rect.fromLTWH(0, 0, 100, 100);
const double borderWidth = 2.0;
const UnderlineInputBorder border = UnderlineInputBorder(
borderSide: BorderSide(width: borderWidth),
);
expect(
(Canvas canvas) => border.paint(canvas, canvasRect),
paints
..line(
p1: Offset(0, canvasRect.height - borderWidth / 2),
p2: Offset(100, canvasRect.height - borderWidth / 2),
strokeWidth: borderWidth,
),
);
});
testWidgets('InputDecorator OutlineBorder focused label with icon', (WidgetTester tester) async {
// This is a regression test for https://github.com/flutter/flutter/issues/82321
Widget buildFrame(TextDirection textDirection) {
@ -5174,42 +5227,6 @@ void main() {
});
});
testWidgets('UnderlineInputBorder clips top border to prevent anti-aliasing glitches', (WidgetTester tester) async {
const Rect canvasRect = Rect.fromLTWH(0, 0, 100, 100);
const UnderlineInputBorder border = UnderlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
);
expect(
(Canvas canvas) => border.paint(canvas, canvasRect),
paints
..drrect(
outer: RRect.fromLTRBAndCorners(0.0, 0.0, 100.0, 100.5,
bottomRight: const Radius.elliptical(12.0, 12.5),
bottomLeft: const Radius.elliptical(12.0, 12.5)),
inner: RRect.fromLTRBAndCorners(0.0, 0.0, 100.0, 99.5,
bottomRight: const Radius.elliptical(12.0, 11.5),
bottomLeft: const Radius.elliptical(12.0, 11.5)),
),
);
const UnderlineInputBorder border2 = UnderlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(60.0)),
);
expect(
(Canvas canvas) => border2.paint(canvas, canvasRect),
paints
..drrect(
outer: RRect.fromLTRBAndCorners(0.0, 0.0, 100.0, 100.5,
bottomRight: const Radius.elliptical(50.0, 50.5),
bottomLeft: const Radius.elliptical(50.0, 50.5)),
inner: RRect.fromLTRBAndCorners(0.0, 0.0, 100.0, 99.5,
bottomRight: const Radius.elliptical(50.0, 49.5),
bottomLeft: const Radius.elliptical(50.0, 49.5)),
),
reason: 'clamp is expected',
);
});
testWidgets('Ensure the height of labelStyle remains unchanged when TextField is focused', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/141448.
final FocusNode focusNode = FocusNode();
@ -9754,12 +9771,12 @@ void main() {
expect(box, paints
..drrect(
style: PaintingStyle.fill,
inner: RRect.fromLTRBAndCorners(0.0, 0.0, 800.0, 47.5,
bottomRight: const Radius.elliptical(12.0, 11.5),
bottomLeft: const Radius.elliptical(12.0, 11.5)),
outer: RRect.fromLTRBAndCorners(0.0, 0.0, 800.0, 48.5,
bottomRight: const Radius.elliptical(12.0, 12.5),
bottomLeft: const Radius.elliptical(12.0, 12.5)),
inner: RRect.fromLTRBAndCorners(0.0, 0.0, 800.0, 47.0,
bottomRight: const Radius.elliptical(12.0, 11.0),
bottomLeft: const Radius.elliptical(12.0, 11.0)),
outer: RRect.fromLTRBAndCorners(0.0, 0.0, 800.0, 48.0,
bottomRight: const Radius.elliptical(12.0, 12.0),
bottomLeft: const Radius.elliptical(12.0, 12.0)),
));
});