Skip to content

Fix text selection toolbar appearing under obstructions - #29809

Merged
LongCatIsLooong merged 16 commits into
flutter:masterfrom
jiisd:fix/issues_29808
May 6, 2019
Merged

LongCatIsLooong merged 16 commits into
flutter:masterfrom
jiisd:fix/issues_29808

Conversation

@jiisd

@jiisd jiisd commented Mar 22, 2019 •

Copy link
Copy Markdown
Contributor

Fixed an issue described in this link
#29808

Description

If the distance from the top is less than a certain value, the toolbar should be displayed below the input box.
If don't do this, the toolbar will be displayed incorrectly on top of some phones and cannot be clicked, such as iPhone X or some Android models.

iPhone 6SP (Flutter, this branch):
fix_flutter_issues_29808_2_2

iPhone XR (Flutter, this branch):
fix_flutter_issues_29808_3

Android (Flutter, this branch):
fix_flutter_issues_29808_1

@googlebot

Copy link
Copy Markdown

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here (e.g. I signed it!) and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@goderbauer goderbauer added framework flutter/packages/flutter repository. See also f: labels. p: material_ui material_ui package in flutter/packages p: cupertino_ui cupertino_ui package in flutter/packages labels Mar 22, 2019
@xster
xster requested a review from justinmc April 8, 2019 19:48
@xster

xster commented Apr 8, 2019

Copy link
Copy Markdown
Member

@justinmc could you take a first pass at this?

@justinmc justinmc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this strategy, it looks good overall and my only comments are just a small few code quality things.

We do need to decide if this is the right overall approach for this problem though. I meant to try running this code myself, but I'm on airport internet and I think it's blocking Flutter from updating itself. Assuming it works in all cases though, the code is pretty simple and unintrusive. My main concern is that Tooltip does something similar and there is currently no code reuse between that solution and this one. I'm talking about _TooltipPositionDelegate and positionDependentBox.

Hoping to start a discussion and see what other people think.

Comment thread packages/flutter/lib/src/widgets/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/widgets/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/widgets/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/cupertino/text_selection.dart Outdated
@googlebot

Copy link
Copy Markdown

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@googlebot googlebot added cla: yes and removed cla: no labels Apr 9, 2019
@justinmc

justinmc commented Apr 9, 2019

Copy link
Copy Markdown
Contributor

@jiisd Check out the failures under the "analyze" check when you get a chance. There are some small linter failures to fix.

@jiisd

jiisd commented Apr 9, 2019

Copy link
Copy Markdown
Contributor Author

@jiisd Check out the failures under the "analyze" check when you get a chance. There are some small linter failures to fix.

🙂 already fixed.

@justinmc

justinmc commented Apr 9, 2019

Copy link
Copy Markdown
Contributor

Thank you!

One more thing that I forgot to mention, sorry. This will definitely need tests.

There are similar tests for the selection menu in https://github.com/flutter/flutter/blob/master/packages/flutter/test/material/text_field_test.dart#L887. You can reuse some of that code to get the selection menu to appear in your test. Then get its location with something like tester.getTopLeft(find.text('SELECT ALL')) and expect it to be above the TextField when it's not near the top of the screen and below the TextField when it is near the top of the screen.

@matthew-carroll

Copy link
Copy Markdown
Contributor

CC @xster @LongCatIsLooong we should check the native iOS behavior, and then pull down this branch and compare.

@jiisd

jiisd commented Apr 10, 2019

Copy link
Copy Markdown
Contributor Author

Thank you!

One more thing that I forgot to mention, sorry. This will definitely need tests.

There are similar tests for the selection menu in https://github.com/flutter/flutter/blob/master/packages/flutter/test/material/text_field_test.dart#L887. You can reuse some of that code to get the selection menu to appear in your test. Then get its location with something like tester.getTopLeft(find.text('SELECT ALL')) and expect it to be above the TextField when it's not near the top of the screen and below the TextField when it is near the top of the screen.

Thanks for your reminder!

The corresponding regression test logic has been added(this commit).

➜ flutter git:(fix/issues_29808) ✗ flutter test /Users/yaheng/.flutter_lib/packages/flutter/test/material/text_field_test.dart
00:10 +130: All tests passed!

@justinmc

Copy link
Copy Markdown
Contributor

@jiisd The test looks good, thanks. I confirmed that it fails without this fix.

How do you feel about increasing the distance from the input to the menu in Android so that the selection handles are visible? It looks like native Android positions the menu so that the handles are visible.

Android (native):
Screenshot_20190410-090547

iOS looks fine I think, except problems unrelated to this PR like the position of the arrow.

iOS (native):
Screen Shot 2019-04-10 at 9 25 51 AM

iOS (Flutter, this branch):
Screen Shot 2019-04-10 at 9 24 43 AM

@jiisd

jiisd commented Apr 10, 2019

Copy link
Copy Markdown
Contributor Author

@justinmc Yep, on android, I think your idea of increasing distance is very appropriate and can make the user experience better.
On iOS, I have tried to make the arrow to adjust the left and right position dynamically before, but I haven't found an elegant solution. If I progress, I will submit the relevant PR again.

@justinmc

Copy link
Copy Markdown
Contributor

Thanks. This is the issue about the arrow position FYI: #22576

@xster

xster commented Apr 10, 2019

Copy link
Copy Markdown
Member

The iOS arrow can be done in a separate PR (if you'd like to keep sending us PR :D)

It's tracked in #11274

@xster xster left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for your contribution. Some comments.

Comment thread packages/flutter/lib/src/cupertino/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/cupertino/text_selection.dart
Comment thread packages/flutter/lib/src/cupertino/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/cupertino/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/cupertino/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/cupertino/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/material/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/material/text_selection.dart Outdated

@justinmc justinmc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR is just about ready. @xster What do you think now that your review has been addressed?

Comment thread packages/flutter/lib/src/cupertino/text_selection.dart Outdated

@xster xster left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for your patience! This PR looks great now.

The test seems unrelated. Can you rebase your branch to the head of master and push again? It's probably something else on the master branch where you branched from.

Please draft a message for the community regarding the breaking change of adding another parameter to buildToolbar based on https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes.

You may not have permission to send an announcement to flutter-announce. In that case, you can just write the message in markdown and post it in this github PR thread and I'll forward it.

Comment thread packages/flutter/lib/src/cupertino/text_selection.dart Outdated
Comment thread packages/flutter/lib/src/widgets/text_selection.dart
Comment thread packages/flutter/test/material/text_field_test.dart
@jiisd

jiisd commented Apr 30, 2019 •

Copy link
Copy Markdown
Contributor Author

@xster Thanks!

[Breaking Change] The public interface of the abstract class TextSelectionControls

Description

When repairing the problem of #29808, it found that the interface is no longer sufficient. In order to get a more accurate anchor point for the toolbar, some parameters are added to the relevant interface. You can get more details form #29809.

The path of the change class lib/src/widgets/text_selection.dart line:90.

Previous interface definition:

  /// Builds a toolbar near a text selection.
  ///
  /// Typically displays buttons for copying and pasting text.
  Widget buildToolbar(BuildContext context, Rect globalEditableRegion, Offset position, TextSelectionDelegate delegate);

Current interface definition:

  /// Builds a toolbar near a text selection.
  ///
  /// Typically displays buttons for copying and pasting text.
  ///
  /// [globalEditableRegion] is the TextField size of the global coordinate system
  /// in logical pixels.
  ///
  /// The [position] is a general calculation midpoint parameter of the toolbar.
  /// If you want more detailed position information, can use [endpoints]
  /// to calculate it.
  Widget buildToolbar(
    BuildContext context,
    Rect globalEditableRegion,
    Offset position,
    List<TextSelectionPoint> endpoints,
    TextSelectionDelegate delegate,
  );

How to update

If you have already used this interface, you should update it to the latest version and add the endpoints parameter.
We keep the position parameter because we think it's probably already used in subclasses.

@justinmc

Copy link
Copy Markdown
Contributor

@xster Any idea on the test failure? It seems unrelated. Something about gradle.

@xster xster changed the title FIX Issues 29808:Cannot interact when using TextField at the top of t… Fix text selection toolbar appearing under obstructions Apr 30, 2019
@justinmc

justinmc commented May 1, 2019

Copy link
Copy Markdown
Contributor

The failure went green after a rerun. I think this is ready to merge.

@xster

xster commented May 1, 2019

Copy link
Copy Markdown
Member

Yup, LGTM

I copy edited the message a bit. @jiisd if you're ok with the edit, I'll send it out and give the community a day to give feedback. Thanks again for the fix.

[Breaking Change] TextSelectionControls.buildToolbar signature adds another 'endpoint' argument

If you don't implement your own TextSelectionControls subclass, you can stop reading.

Description

While fixing the problem of #29808, it was found that the TextSelectionControls.buildToolbar interface is no longer sufficient to adequately replicate the native behavior. In order to get a more accurate anchor point for the text selection toolbar, the selection's start and end positions are added to the function signature. You can get more details form #29809.

In lib/src/widgets/text_selection.dart:

Previous interface definition

  /// Builds a toolbar near a text selection.
  ///
  /// Typically displays buttons for copying and pasting text.
  Widget buildToolbar(
    BuildContext context, 
    Rect globalEditableRegion, 
    Offset position, 
    TextSelectionDelegate delegate,
  );

becomes

  /// Builds a toolbar near a text selection.
  ///
  /// Typically displays buttons for copying and pasting text.
  ///
  /// [globalEditableRegion] is the TextField size of the global coordinate system
  /// in logical pixels.
  ///
  /// The [position] is a general calculation midpoint parameter of the toolbar.
  /// If you want more detailed position information, can use [endpoints]
  /// to calculate it.
  Widget buildToolbar(
    BuildContext context,
    Rect globalEditableRegion,
    Offset position,
    List<TextSelectionPoint> endpoints,
    TextSelectionDelegate delegate,
  );

Specifically List<TextSelectionPoint> endpoints was added.

How to update

If you currently implement this interface, you should update its signature to the latest version and add the endpoints parameter.
For backward compatibility, the position parameter (which is the midpoint between the 2 endpoint positions) was preserved.

@jiisd

jiisd commented May 2, 2019

Copy link
Copy Markdown
Contributor Author

@xster Awesome thanks!

@xster

xster commented May 2, 2019

Copy link
Copy Markdown
Member

Actually on second thought, I sent you an invite to join our flutter-announce google group (to your 163.com). You can send the breaking change announcement yourself once you accept the invitation.

@jiisd

jiisd commented May 2, 2019 •

Copy link
Copy Markdown
Contributor Author

@xster The email from 163.com was rejected. Can you invite another account(gmail.com)?
Thanks!

@xster

xster commented May 2, 2019

Copy link
Copy Markdown
Member

Thanks, sent

@jiisd

jiisd commented May 2, 2019 •

Copy link
Copy Markdown
Contributor Author

Still failing, is the target email address of [email protected] incorrectly?

@xster

xster commented May 2, 2019

Copy link
Copy Markdown
Member

Sorry, one of the permission settings wasn't set correctly. Your gmail address should have posting rights now.

@jiisd

jiisd commented May 2, 2019 •

Copy link
Copy Markdown
Contributor Author

It works!
Thanks.

@dkwingsmt

dkwingsmt commented May 2, 2019 •

Copy link
Copy Markdown
Contributor

Since we’re breaking the API, is it better to make parameters into a Details object (as in here) so that we can add more information in the future without breaking the code again and without having too many parameters?

@xster

xster commented May 3, 2019

Copy link
Copy Markdown
Member

I think it's mostly ok. The gesture events is a highly public API used by callback implementers everywhere.

Since we might change the arguments in any signature in the future, the argument can be generally applied to all functions having a single data class as argument so it's non-breaking-modifiable :D

So we'd have to draw the line somewhere and for subclass overrides, I think it's ok.

@LongCatIsLooong
LongCatIsLooong merged commit 57d6666 into flutter:master May 6, 2019
@justinmc

justinmc commented May 6, 2019

Copy link
Copy Markdown
Contributor

Thanks so much for fixing this @jiisd!

@FrankYan09

Copy link
Copy Markdown

we use Flutter 1.7.8+hotfix.4, still have this issue.

@LongCatIsLooong

LongCatIsLooong commented Aug 2, 2019 •

Copy link
Copy Markdown
Contributor

@FrankYan09 could you create a new issue here https://github.com/flutter/flutter/issues/new/choose, preferably with screenshots and code to reproduce the issue so we would be able to identify the problem quickly?

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Aug 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

framework flutter/packages/flutter repository. See also f: labels. p: cupertino_ui cupertino_ui package in flutter/packages p: material_ui material_ui package in flutter/packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants