From fe0e219b9e867d3794b51bc61652faa740e73954 Mon Sep 17 00:00:00 2001 From: Flop <38378650+hgraceb@users.noreply.github.com> Date: Wed, 11 Dec 2024 04:32:45 +0800 Subject: [PATCH] Adjust the drawing position of OutlineInputBorder (#159943) Fixes #159942 Related Discussion: [#158440 (comment)](https://github.com/flutter/flutter/pull/158440#discussion_r1844902638) ## Temporary code - Change the background color of the label container. https://github.com/flutter/flutter/blob/3f08b617848e26b462560601c4a8b89a93515e77/packages/flutter/lib/src/material/input_decorator.dart#L2216-L2220 ```diff + child: Container( + color: Colors.red.withOpacity(0.2), child: decoration.label ?? Text( decoration.labelText!, overflow: TextOverflow.ellipsis, textAlign: textAlign, ), + ), ``` - Change border width. https://github.com/flutter/flutter/blob/3f08b617848e26b462560601c4a8b89a93515e77/packages/flutter/lib/src/material/input_decorator.dart#L4838 ```diff - return BorderSide(color: _colors.primary, width: 2.0); + return BorderSide(color: _colors.primary, width: 6.0); ``` ## Example code ```dart import 'package:flutter/material.dart'; void main() { runApp( MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( body: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Directionality( textDirection: TextDirection.ltr, child: RepaintBoundary( child: InputDecorator( isFocused: true, isEmpty: true, decoration: InputDecoration( hintText: 'TextDirection.ltr with BorderSide(width: 2.0)', labelText: 'ABCDEFGGFEDCBAABCDEFGGFEDCBAABCDEFGGFEDCBAABCDEFGGFEDCBA', border: OutlineInputBorder( gapPadding: 0.0, ), ), ), ), ), Directionality( textDirection: TextDirection.rtl, child: RepaintBoundary( child: InputDecorator( isFocused: true, isEmpty: true, decoration: InputDecoration( hintText: 'TextDirection.rtl with BorderSide(width: 2.0)', labelText: 'ABCDEFGGFEDCBAABCDEFGGFEDCBAABCDEFGGFEDCBAABCDEFGGFEDCBA', border: OutlineInputBorder( gapPadding: 0.0, ), ), ), ), ), ], ), ), ), ), ); } ``` | Before | After | | ------ | ----- | | ![before1](https://github.com/user-attachments/assets/c4b5ee75-f9f8-4ec0-baa4-7a51430893e6) | ![after1](https://github.com/user-attachments/assets/234b16c5-5a9a-4a1c-9f7e-d58e507533a6) | | ![before2](https://github.com/user-attachments/assets/3afc7668-1a3f-49de-8c61-b839a120a950) | ![after2](https://github.com/user-attachments/assets/fd9e7f13-9da4-4639-9839-a293c77a76cf) | ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../lib/src/material/input_border.dart | 4 +- .../test/material/input_decorator_test.dart | 68 +++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/input_border.dart b/packages/flutter/lib/src/material/input_border.dart index b9d4d8e1e7..af6508f232 100644 --- a/packages/flutter/lib/src/material/input_border.dart +++ b/packages/flutter/lib/src/material/input_border.dart @@ -476,14 +476,14 @@ class OutlineInputBorder extends InputBorder { // Draw top border from top left corner to gap start. if (start > scaledRRect.tlRadiusX) { - path.lineTo(scaledRRect.left + start, scaledRRect.top); + path.lineTo(start, scaledRRect.top); } // Draw top border from gap end to top right corner and draw top right corner. const double trCornerArcStart = (3 * math.pi) / 2.0; const double trCornerArcSweep = cornerArcSweep; if (start + extent < outerWidth - scaledRRect.trRadiusX) { - path.moveTo(scaledRRect.left + start + extent, scaledRRect.top); + path.moveTo(start + extent, scaledRRect.top); path.lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top); if (scaledRRect.trRadius != Radius.zero) { path.addArc(trCorner, trCornerArcStart, trCornerArcSweep); diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 6088f60b32..33a9d894b7 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -1707,6 +1707,74 @@ void main() { ); }); + // Regression test for https://github.com/flutter/flutter/issues/159942. + testWidgets('OutlineBorder does not overlap with the label at the default radius', (WidgetTester tester) async { + Widget buildFrame(TextDirection textDirection) { + return MaterialApp( + home: Scaffold( + body: Container( + padding: const EdgeInsets.all(16.0), + alignment: Alignment.center, + child: Directionality( + textDirection: textDirection, + child: const RepaintBoundary( + child: InputDecorator( + isFocused: true, + decoration: InputDecoration( + labelText: labelText, + border: OutlineInputBorder( + gapPadding: 0.0, + ), + ), + ), + ), + ), + ), + ), + ); + } + + await tester.pumpWidget(buildFrame(TextDirection.ltr)); + Rect labelRect = getLabelRect(tester); + RenderBox borderBox = InputDecorator.containerOf(tester.element(findBorderPainter()))!; + expect(findBorderPainter(), paints + ..save() + ..path( + // The points of the label edge should be part of the border. + includes: [ + borderBox.globalToLocal(labelRect.centerLeft), + borderBox.globalToLocal(labelRect.centerRight), + ], + // The points inside the label should not be part of the border. + excludes: [ + borderBox.globalToLocal(labelRect.centerLeft) + const Offset(1, 0), + borderBox.globalToLocal(labelRect.centerRight) + const Offset(-1, 0), + ], + ) + ..restore(), + ); + + await tester.pumpWidget(buildFrame(TextDirection.rtl)); + labelRect = getLabelRect(tester); + borderBox = InputDecorator.containerOf(tester.element(findBorderPainter()))!; + expect(findBorderPainter(), paints + ..save() + ..path( + // The points of the label edge should be part of the border. + includes: [ + borderBox.globalToLocal(labelRect.centerLeft), + borderBox.globalToLocal(labelRect.centerRight), + ], + // The points inside the label should not be part of the border. + excludes: [ + borderBox.globalToLocal(labelRect.centerLeft) + const Offset(1, 0), + borderBox.globalToLocal(labelRect.centerRight) + const Offset(-1, 0), + ], + ) + ..restore(), + ); + }); + testWidgets('OutlineBorder does not draw over label when input decorator is focused and has an icon', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/18111. Widget buildFrame(TextDirection textDirection) {