-
Notifications
You must be signed in to change notification settings - Fork 29.1k
Multiline Selection Menu Position Bug #36974
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiline Selection Menu Position Bug #36974
Conversation
It looks like this pull request may not have tests. Please make sure to add tests before merging. While there are exceptions to this rule, if this patch modifies code it is probably not an exception. Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. /cc @dnfield |
@LongCatIsLooong Requesting a review from you because of your recent cleanup of the Cupertino text selection postioning code (#34095). Cupertino's behavior seems perfect after your PR, but apparently Material's was still buggy. I tried to copy your approach a bit for Material, let me know what you think or if I missed anything though. |
0d565af
to
9be3399
Compare
@@ -305,11 +305,12 @@ class _CupertinoTextSelectionControls extends TextSelectionControls { | |||
// The toolbar should appear below the TextField when there is not enough | |||
// space above the TextField to show it, assuming there's always enough space | |||
// at the bottom in this case. | |||
final bool isArrowPointingDown = | |||
mediaQuery.padding.top | |||
final double toolbarHeightNeeded = mediaQuery.padding.top |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
: startTextSelectionPoint.point.dy - globalEditableRegion.height; | ||
final double toolbarHeightNeeded = MediaQuery.of(context).padding.top | ||
+ _kToolbarScreenPadding | ||
+ _kToolbarHeight; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there supposed to be a non-zero content padding (between the paragraph and the bottom of the toolbar)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem so looking at the code, but looking at native apps it seems like there should be. I'll add in a _kToolbarContentDistance
like in iOS. It may break golden/scuba tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+ _kToolbarHeight; | ||
final double availableHeight = globalEditableRegion.top + endpoints.first.point.dy - textLineHeight; | ||
final bool fitsAbove = toolbarHeightNeeded <= availableHeight; | ||
final double y = fitsAbove |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment here
flutter/packages/flutter/lib/src/material/text_selection.dart
Lines 81 to 83 in 9be3399
/// Anchor position of the toolbar, relative to the top left of the | |
/// [globalEditableRegion]. | |
final Offset position; |
Makes it really confusing. I guess instead of anchor it should say bottom left? And the fact that we use bottom left instead of top left sounds strange to me too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the value passed in for position is where the center of the toolbar is drawn? If I pass in 0.0
for y, it draws the toolbar so that it's vertical midpoint is on the top of the textfield.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in _TextSelectionToolbarLayout.getPositionForChild
I think _TextSelectionToolbarLayout.position
is used as the coordinate of the bottom left vertex of the toolbar, in global coordinate system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry I was just ranting because it threw me off, It's not really related to this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok got it. Yeah it's definitely confusing.
final bool fitsAbove = toolbarHeightNeeded <= availableHeight; | ||
final double y = fitsAbove | ||
? startTextSelectionPoint.point.dy - textLineHeight | ||
: startTextSelectionPoint.point.dy + _kToolbarHeight + _kToolbarContentDistanceBelow; | ||
final Offset preciseMidpoint = Offset(x, y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really related to the issue, but I think x
is already calculated in TextSelectionOverlay._buildToolbar
. Instead of doing it here again maybe just use position.dx
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah seems to be calculating the same exact value to me. I'll change it.
Waiting on a goldens file update in flutter/goldens#41 |
final Offset firstLineToolbarTopLeft = tester.getTopLeft(find.text('SELECT ALL')); | ||
final Offset firstLineTopLeft = textOffsetToPosition(tester, testValue.indexOf('a')); | ||
expect(firstLineTopLeft.dy, lessThan(firstLineToolbarTopLeft.dy)); | ||
expect(firstLineToolbarTopLeft.dy, greaterThan(firstLineTopLeft.dy)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this line saying the same thing as the line above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good catch!
await tester.tapAt(tester.getCenter(find.byType(EditableText))); | ||
await tester.pump(); | ||
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero | ||
await tester.pumpAndSettle(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to pump a third time here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried it and it seems to be unnecessary, so I'll remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
@@ -499,7 +499,7 @@ void main() { | |||
find.byType(Overlay), | |||
matchesGoldenFile( | |||
'text_field_opacity_test.0.png', | |||
version: 2, | |||
version: 3, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Description
The selection menu is showing up in the wrong place for multiline inputs in Material.
Related Issues
Closes #36749
Tests
Wrote a multiline input test that checks the position of the selection menu.