8000 added new ScrollViewKeyboardDismissBehavior variant onScroll with tests by nick9822 · Pull Request #160507 · flutter/flutter · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

added new ScrollViewKeyboardDismissBehavior variant onScroll with tests #160507

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

nick9822
Copy link
Contributor
@nick9822 nick9822 commented Dec 18, 2024

Previously ScrollViewKeyboardDismissBehavior was limited in handling scroll events, proposal in this PR is to introduce a new variant onScroll which is for dismissing on-screen keyboard for all user-initiated scrolls which includes (non-drag) scrolls common on desktops (mouse scroll, two-finger scrolls) (#154515).

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • 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.
  • All existing and new tests are passing.

@@ -44,6 +44,9 @@ enum ScrollViewKeyboardDismissBehavior {
/// `onDrag` means that the [ScrollView] will dismiss an on-screen keyboard
/// when a drag begins.
onDrag,
/// `noDrag` means that the [ScrollView] will dismiss an on-screen keyboard
/// when a scroll begins irrespective of a drag.
noDrag,
Copy link
Contributor

Choose a reason for hiding this comment

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

With noDrag, will the on-screen keyboard be dismissed on any scroll? If yes, onScroll might be a better name for it, since dragging is only one of many ways to scroll, so we probably don't want a 'drag'-specific name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, onScroll makes sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

In the documentation for this new value, we should mention that when the keyboard opens and pushes the field to make it still visible, it will send a scroll notification that will cause the field to immediately be unfocused. Possibly breadcrumb to the issue, at least in a private comment.

Copy link
Contributor 8000 Author

Choose a reason for hiding this comment

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

The said notification sends a scroll without a drag, so after we merge this PR

  • It will work as expected to the users who will use ScrollViewKeyboardDismissBehavior.onDrag because field will not be unfocused (because there is no drag).
  • but field will be unfocused immediately for the users who used ScrollViewKeyboardDismissBehavior.onScoll (irrespective of the drag).

Not sure about the right place for the documentation but as you said we can add breadcrumb to the issues #154515 or #150048 for the information on when to use onScroll vs onDrag.

Copy link
Contributor

Choose a reason for hiding this comment

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

We can just add to the documentation for onScroll that it should be used to dismiss the keyboard on all scrolls (with a drag, trackpad, mouse wheel etc). And then add the caveat that because we are watching for all scroll notifications, programmatic scrolls will also dismiss the keyboard (e.g the keyboard scrolling to keep the field visible, etc). That should be enough in the API docs. Then in the implementation we can just add a comment to breadcrumb to the relevant issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@victorsanni renamed the variant and updated comment.

@victorsanni
Copy link
Contributor

Thanks for the PR. I'm leaning towards just reverting #154675 and reopening the linked issues. The core problem is that we have no way of tracking trackpad scrolls with ScrollNotification, only drag scrolls (via ScrollUpdateNotification.dragDetails). Removing the check for a drag (notification.dragDetails != null) will unfocus the contents of the scroll view anytime a scroll notification comes in, which is causing the bug in #160331.

@victorsanni
Copy link
Contributor

Thanks for the PR. I'm leaning towards just reverting #154675 and reopening the linked issues. The core problem is that we have no way of tracking trackpad scrolls with ScrollNotification, only drag scrolls (via ScrollUpdateNotification.dragDetails). Removing the check for a drag (notification.dragDetails != null) will unfocus the contents of the scroll view anytime a scroll notification comes in, which is causing the bug in #160331.

I played around with it a little more and I saw that drags still dismiss the keyboard. However, the issue occurs when the focused field is within the bounds of where the keyboard appears, so when the keyboard opens it scrolls to push the field up so that it remains visible. That sends a scroll notification that then unfocuses the field.

Instead of increasing the API surface, can we add a fix to ignore these types of scrolls when unfocusing?

@nick9822
Copy link
Contributor Author
nick9822 commented Jan 6, 2025

Some scrolls produces a drag while others not. I think increasing the API surface will make the usage clear as to when to dismiss the keyboard manual, onDrag or onScroll.

If we don't want to increase the API surface, we need to unfocus the field when it goes out of the view which will fix #154515, #150048. This way we can revert #154675.

@victorsanni
Copy link
Contributor

It makes sense to add an onScroll in the short term. But that will only propagate the bug to that value instead.

The long-term solution imo should be to expose if the on-screen keyboard's opening triggered a scroll notification, and just ignore those notifications. But that would be quite an undertaking, so as long as we warn users clearly enough I'm fine with moving forward with this change.

What do you think @justinmc @nick9822 ?

@nick9822
Copy link
Contributor Author
nick9822 commented Jan 6, 2025

@victorsanni Currently we don't have enough information in the notification to find trigger behind the scroll. I think making it available will be a significant change.

However if we merge this PR, it actually reverses #154675 and allows users to control the dismiss behavior onScroll, the behavior required in the issues #154515, #150048. But we will need to communicate/warn.

@goderbauer goderbauer requested a review from Piinks January 7, 2025 23:11
@Piinks
Copy link
Contributor
Piinks commented Jan 8, 2025

However if we merge this PR, it actually reverses #154675 and allows users to control the dismiss behavior onScroll, the behavior required in the issues #154515, #150048. But we will need to communicate/warn.

I agree with @victorsanni.
We should revert the original PR that introduced the regression in a separate change first instead of fixing forward here. We should then cherry pick that revert to the stable branch since the regression was shipped in the last release.

After that we can revisit this and determine how to fix the original issues properly.

@nick9822 nick9822 force-pushed the new_variant_keyboardDismissBehavior_noDrag branch from 047dea7 to 73ae283 Compare January 10, 2025 12:01
/// Caveat: Since we are watching for all scroll notifications, programmatic
/// scrolls will also dismiss the keyboard (e.g opening of on-screen keyboard
/// produces a scroll to keep the field visible).
onScroll,
Copy link
Contributor

Choose a reason for hiding this comment

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

Hi @nick9822. The linked issues are both in the Autocomplete widget. Can we explore a fix contained within that widget?

Alternatively, in NotificationListener.onNotification:

  • @Piinks suggested an approach to expose what device triggered the notification, or
  • Expose if a scroll was triggered programmatically or manually.
  • or another solution I can't currently think of.

The bug in #160331 is quite severe, and propagating it into a new enum value doesn't seem like the right fix even if we do warn users.

Copy link
Contributor Author
@nick9822 nick9822 Jan 22, 2025

Choose a reason for hiding this comment

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

@victorsanni I don't think this PR propagate the issue #160331, for that matter after the recent regression issue #160331 and this PR have no relation. This just extends the API surface giving user a choice to strictly dismiss keyboard on scroll.

I agree both issues #154515, #150048 are around Autocomplete and we can explore fix in that widget. #150048 actually makes sense because those scrolls doesn't produce any taps and hence focus remain unchanged specifically on Desktops. But #154515 seems like a UI defect which I think needs a fix.

Not sure on how @Piinks suggestions will help.

8000

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this PR propagate the issue

The issue is that programmatic scrolls will dismiss the keyboard. If a user uses .onScroll, with this implementation, unintended programmatic scrolls like autoscrolling to keep a text field visible will dismiss the keyboard too, which is undesired. That's the crux of #160331.

If .onScroll can filter unintended programmatic scrolls from intended scrolls, then I think it would be a nice addition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay, I will try to filter programmatic scrolls.

@flutter-dashboard
Copy link

This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@justinmc
Copy link
Contributor

@nick9822 Just checking, do you still plan to return to finish this PR?

@nick9822
Copy link
Contributor Author

@nick9822 Just checking, do you still plan to return to finish this PR?

@justinmc Yes will take it in a week or two.

@justinmc
Copy link
Contributor
justinmc commented Apr 8, 2025

@nick9822 Another friendly reminder here on this PR, do you plan to return to it? No worries if you still need time.

@nick9822
Copy link
Contributor Author
nick9822 commented Apr 9, 2025

@nick9822 Another friendly reminder here on this PR, do you plan to return to it? No worries if you still need time.

Yes @justinmc, I should be able to work it this month.

@nick9822 nick9822 force-pushed the new_variant_keyboardDismissBehavior_noDrag branch from 0fbc070 to 0a0b6a9 Compare May 6, 2025 13:00
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.

Hey @nick9822! I saw some updates pushed here, is this ready for another review?
The analyzer is a bit unhappy, but let us know if this is ready for another look!

@nick9822
Copy link
Contributor Author

Hey @nick9822! I saw some updates pushed here, is this ready for another review? The analyzer is a bit unhappy, but let us know if this is ready for another look!

It's in progress, will be ready for review soon.

@nick9822 nick9822 force-pushed the new_variant_keyboardDismissBehavior_noDrag branch from 0a0b6a9 to fed964e Compare May 21, 2025 19:11
@nick9822 nick9822 changed the title added new ScrollViewKeyboardDismissBehavior variant onDrag with tests added new ScrollViewKeyboardDismissBehavior variant onScroll with tests May 21, 2025
@nick9822 nick9822 requested review from victorsanni and Piinks May 22, 2025 08:29
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.

Hey @nick9822 thanks for the updates! Can you update the PR description to reflect the latest version here?

@@ -225,11 +231,15 @@ abstract class ViewportOffset extends ChangeNotifier {
/// like [ScrollPosition] handle it by adjusting [to] to prevent over or
/// underscroll.
Future<void> moveTo(double to, {Duration? duration, Curve? curve, bool? clamp}) {
isProgrammaticScroll = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know that this is necessarily true. The user could call any of the methods here, moveTo, jumpTo, animateTo - all of those would be programmatic. What is the difference here?
Scroll actions, like in response to keyboard input call moveTo, scrollbars use moveTo, as do the methods for showing something in a viewport.

Copy link
Contributor Author
@nick9822 nick9822 May 31, 2025

Choose a reason for hiding this comment

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

I saw moveTo being used when the screen is being scrolled programmatically especially when the soft-keyboard is opened and the text field needs to be in focus. I think moveTo is only used when scroll happens without user directly intending to scroll (mostly show in viewport cases) only exception is scrollbar taps where page is scrolled towards the direction. In scroll taps we could have directly used animateTo instead of moveTo.

Anyways as you said jumpTo, animateTo are also programmatic in a sense, may be the name should be unintendedScroll. This was attempt towards the last review by @victorsanni

The issue is that programmatic scrolls will dismiss the keyboard. If a user uses .onScroll, with this implementation, unintended programmatic scrolls like autoscrolling to keep a text field visible will dismiss the keyboard too, which is undesired. That's the crux of #160331.

If .onScroll can filter unintended programmatic scrolls from intended scrolls, then I think it would be a nice addition.

I think filtering out unintendedScroll should be the target here.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think moveTo can be assumed to always be used this way. It is public API that anyone could be using in any number of ways, like I mentioned with scrollbars. That is calling moveTo in response to the user dragging on the scrollbar. So I don't think this is a safe assumption to make unfortunately.

@@ -119,6 +119,12 @@ abstract class ViewportOffset extends ChangeNotifier {
/// correction.
factory ViewportOffset.zero() = _FixedViewportOffset.zero;

/// Whether the current offset change was due to programmatic scroll.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is a programmatic scroll?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Automated scrolls (non-user initiated)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0