Skip to content

Conversation

@justinmc
Copy link
Contributor

@justinmc justinmc commented May 3, 2022

Previously, edge scrolling was incorrect if it caused a Scrollable to scroll. Our math only considered scrolling the RenderEditable itself, but not a containing Scrollable. This PR fixes this by taking both into consideration.

Old New
out out

The problem

Drag gestures in GestureDetector don't consider scrolling that happens during the event, as demonstrated in this dartpad. Because of this, we have to compensate for the scrolling manually when calculating the selection area during edge scrolling.

The scrolling location is not manually calculated, it's just done via renderEditable.showOnScreen, so we don't have the calculated scroll position anywhere.

Previously, this compensation was done only for scrolling that happens inside the RenderEditable (here). However, it's also possible that a tall text input in a small Scrollable causes the Scrollable to scroll (example in the issue), not the RenderEditable, and this must be compensated for, too.

The current solution

Grab the scroll position using Scrollable.of(context).position.pixels and use it to compensate for any scrolling when calculating the selection Rect.

Related

Fixes #102484
Partially fixes #104500 (desktop only fix)

@justinmc justinmc requested a review from Piinks May 3, 2022 20:55
@justinmc justinmc self-assigned this May 3, 2022
@flutter-dashboard flutter-dashboard bot added a: text input Entering text in a text field or keyboard related problems f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. labels May 3, 2022
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

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

I know passing around BuildContext isn't ideal.. looking a bit more into this, it looks like you could do this another way.

Let me know if I am off here, but it looks like the Scrollable in EditableTextState is the one you are after. Instead of looking it up using a context, it may be cleaner to refactor the ScrollController logic of that Scrollable.

If you were able to access the scroll controller, you could access the position similarly without a build context.

ScrollController get _scrollController => widget.scrollController ?? (_internalScrollController ??= ScrollController());

I am not super familiar with editable text, but from what I can tell, a user-provided scroll controller is passed down from the higher level classes like TextField.scrollController and CupertinoTextField.scrollController. If the user has not provided a ScrollController, one is created all the way down in EditableTextState as a fallback.

If instead, you were to take the fallback creation out of EditableTextState and instead create the fallback controller in the higher level classes, the controller (whether it is user provided or the fallback) can be passed to the *TextSelectionGestureDetectorBuilders and then in turn passed further down to EditableTextState. That would remove the need to call Scrollable.of, and no passing around a context that could become invalid.

What do you think? Let me know if you have questions or if I've been unclear. :)

@justinmc
Copy link
Contributor Author

justinmc commented May 5, 2022

@Piinks Actually I explicitly need the Scrollable above the EditableText, not inside of it. Previously we were compensating only for scrolling inside of the EditableText (done here with renderEditable.offset). This PR aims to compensate for any scrolling happening above the EditableText in the widget tree. The issue has an example.

I'll see if I can do this in a cleaner way at all. I'll tag you for re-review.

@Piinks
Copy link
Contributor

Piinks commented May 6, 2022

Oh! Ok, sorry I did not realize. :) So there may, or may not, be an enclosing Scrollable above the TextField. I think in this case then, Scrollable.of if the best approach. Since the Scrollable is outside of the TextField, there is not another way for it to know about it.

@justinmc justinmc force-pushed the input-scrollable-offset branch from a7775bf to c357cc3 Compare May 27, 2022 18:56
@Hixie
Copy link
Contributor

Hixie commented Sep 28, 2022

Hey @justinmc, is this PR still on your radar?

@justinmc
Copy link
Contributor Author

Ah I had forgotten about it, will bring it back to life.

@justinmc justinmc marked this pull request as ready for review September 29, 2022 21:04
@justinmc justinmc requested a review from Piinks September 29, 2022 21:04
@justinmc
Copy link
Contributor Author

@Piinks This is ready for review again. Sorry for the long delay since you last reviewed, but I've now used the Scrollable.of approach and cleaned up the PR.

Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

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

Hopefully will also fix #104500

Does the rework fix this now? It looks like the last update to OP and the issue was May 27

testWidgets('Mouse edge scrolling works in an outer scrollable', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102484
final TextEditingController controller = TextEditingController(
text: 'I love flutter!\n' * 8,
Copy link
Contributor

Choose a reason for hiding this comment

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

Best test content ever. 😜

Comment on lines 2153 to 2159
final ScrollableState? scrollableState =
delegate.editableTextKey.currentContext == null
? null
: Scrollable.of(delegate.editableTextKey.currentContext!);
final double currentScrollDy = scrollableState == null
? 0.0
: scrollableState.position.pixels;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this and the same chunk of lines starting at 2122 be wrapped up in a method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, good call. 9cdd2b1

Co-authored-by: Kate Lovett <[email protected]>
@justinmc
Copy link
Contributor Author

justinmc commented Oct 5, 2022

I tried it and this seems to only fully fix #104500 on desktop. I'll update that issue.

Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

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

Thanks for checking on the other issue. This LGTM!

@justinmc justinmc merged commit d440ee8 into flutter:master Oct 5, 2022
@justinmc justinmc deleted the input-scrollable-offset branch October 5, 2022 23:27
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Oct 6, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Oct 6, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Oct 6, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Oct 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implementation of EditableTextState._scheduleShowCaretOnScreen TextField does not scroll when selecting text

3 participants