Skip to content

Conversation

gspencergoog
Copy link
Contributor

Description

This adds the ability to scroll and page up/down in a Scrollable using the keyboard. Currently, the macOS bindings use Platform.isMacOS as a check, but we'll switch that to be defaultTargetPlatform == TargetPlatform.macOS once that exists.

Related Issues

Tests

  • Added a test for keyboard scrolling both horizontally and vertically.

Breaking Change

  • No, this is not a breaking change.

@gspencergoog gspencergoog added framework flutter/packages/flutter repository. See also f: labels. a: desktop Running on desktop labels Nov 16, 2019
@gspencergoog gspencergoog changed the title Keyboard scroll Keyboard scrolling of Scrollable Nov 16, 2019
@goderbauer
Copy link
Member

Looks like cirrus is unhappy :(

@@ -267,4 +270,85 @@ void main() {

expect(getScrollOffset(tester), 20.0);
});

testWidgets('Vertical scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async {
Copy link
Member

Choose a reason for hiding this comment

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

Can you add more tests to ensure that it scrolls in the right direction when "reverse: true" and when a "center" sliver is used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I added some, which highlighted that I needed to change how I specified direction, so it's now an Axis and a reverse bool instead of an AxisDirection, so it can be resolved with the current directional environment.

What do you mean by "center sliver"? I'm not sure what that should look like.

@gspencergoog gspencergoog force-pushed the keyboard_scroll branch 4 times, most recently from 988ba7f to 28c9bb9 Compare November 19, 2019 08:28
@gspencergoog
Copy link
Contributor Author

I've cleaned this up so that there isn't a new public API on ScrollableState, which didn't turn out to be necessary. PTAL.

@gspencergoog
Copy link
Contributor Author

@goderbauer, can you respond to my comment so I can address yours?

Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

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

LGTM, would defer to @goderbauer on the requested test though

@gspencergoog
Copy link
Contributor Author

Hi, @goderbauer, OK, I think I added the sliver test that we talked about. Please take a look.

@goderbauer
Copy link
Member

Cirrus looks unhappy.

LogicalKeySet(LogicalKeyboardKey.arrowUp): const DirectionalFocusIntent(TraversalDirection.up),

// Directional keyboard traversal. Not available on web.
if (!kIsWeb)
Copy link
Member

Choose a reason for hiding this comment

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

That each line gets its own if reads awkward...

I wonder if this would look nicer with just one if and then the spread operator? Not sure, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it does! Done.


// Keyboard scrolling.
// TODO(gspencergoog): Convert all of the Platform.isMacOS checks to be
// defaultTargetPlatform == TargetPlatform.macOS, once that exists.
Copy link
Member

Choose a reason for hiding this comment

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

nit: link to the issue for this?

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.

/// [ScrollIncrementCalculator] function on a [Scrollable].
///
/// {@template flutter.widgets.scrollable.scroll_increment_type.intent}
/// This indicates the *intent* of the scroll, not necessarily the size. Not all
Copy link
Member

Choose a reason for hiding this comment

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

Nice explanation!

/// Indicates that the [ScrollIncrementCalculator] should return the scroll
/// distance it should move when the user requests to scroll by a "line".
///
/// The distance a "line" scrolls is really refers to what should happen when
Copy link
Member

Choose a reason for hiding this comment

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

Does this sentence have a duplicated verb? "..is really refers to..." sounds strange...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed "is really" (and yes, it was a typo).

/// Indicates that the [ScrollIncrementCalculator] should return the scroll
/// distance it should move when the user requests to scroll by a "page".
///
/// The distance a "page" scrolls is really refers to what should happen when
Copy link
Member

@goderbauer goderbauer Nov 25, 2019

Choose a reason for hiding this comment

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

"... is really refers to..." ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

/// specified.
class ScrollIntent extends Intent {
/// Creates a const [ScrollIntent] that requests scrolling in the given
/// [axis], with the given [type]. If [reversed] is specified, then the scroll
Copy link
Member

Choose a reason for hiding this comment

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

nit: first paragraph should be a one-sentence summary. Move the second sentence to a separate paragraph?

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.

/// widget.
final Axis axis;

/// Whether or not the natural scroll direction for this scroll operation
Copy link
Member

Choose a reason for hiding this comment

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

It's not really clear to me from the doc why we have this property and what it actually means....

Also, what is the "natural scroll direction"? Is that what apple calls natural scrolling? Are we making up our own definition?


/// The direction in which to scroll the scrollable containing the focused
/// widget.
final Axis axis;
Copy link
Member

Choose a reason for hiding this comment

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

Don't you need an AxisDirection? e.g. wether to scroll up or down?

Copy link
Member

Choose a reason for hiding this comment

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

Oh, is that supposed to be indicated by the reversed property?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I switched back to AxisDirection and made sure it worked. I never did discover what made me switch away from it in the first place: maybe an old design was flawed? I also did add a test for RTL locales to make sure that the result was correct there too.

),
home: CustomScrollView(
controller: controller,
physics: const NeverScrollableScrollPhysics(),
Copy link
Member

Choose a reason for hiding this comment

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

Hm, this seems odd. It has NeverScrollableScrollPhysics, but you can still scroll it with the keyboard? That sounds like a bug?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it was. I added a test for this, and fixed the bug.

controller: controller,
physics: const NeverScrollableScrollPhysics(),
slivers: <Widget>[
SliverToBoxAdapter(
Copy link
Member

Choose a reason for hiding this comment

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

Instead of making the test based on scrolloffsets (which are difficult to comprehend since the zero scroll offset may be at the top or bottom) maybe use multiple slivers with text (e.g. sliver 1, sliver 2, etc). and then assert that the expected slivers are currently visible?

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. All based on the rects of the items now.

Copy link
Contributor Author

@gspencergoog gspencergoog left a comment

Choose a reason for hiding this comment

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

OK, @goderbauer, I think I addressed everything we talked about. PTAL.

LogicalKeySet(LogicalKeyboardKey.arrowUp): const DirectionalFocusIntent(TraversalDirection.up),

// Directional keyboard traversal. Not available on web.
if (!kIsWeb)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it does! Done.


// Keyboard scrolling.
// TODO(gspencergoog): Convert all of the Platform.isMacOS checks to be
// defaultTargetPlatform == TargetPlatform.macOS, once that exists.
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.

/// Indicates that the [ScrollIncrementCalculator] should return the scroll
/// distance it should move when the user requests to scroll by a "line".
///
/// The distance a "line" scrolls is really refers to what should happen when
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed "is really" (and yes, it was a typo).

/// Indicates that the [ScrollIncrementCalculator] should return the scroll
/// distance it should move when the user requests to scroll by a "page".
///
/// The distance a "page" scrolls is really refers to what should happen when
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

/// specified.
class ScrollIntent extends Intent {
/// Creates a const [ScrollIntent] that requests scrolling in the given
/// [axis], with the given [type]. If [reversed] is specified, then the 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.

Done.

),
home: CustomScrollView(
controller: controller,
physics: const NeverScrollableScrollPhysics(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it was. I added a test for this, and fixed the bug.

@gspencergoog gspencergoog force-pushed the keyboard_scroll branch 2 times, most recently from 5ef40bd to ed91145 Compare November 25, 2019 22:29
Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

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

LGTM

await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyUpEvent(modifierKey);
await tester.pumpAndSettle();

Copy link
Member

Choose a reason for hiding this comment

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

SHould there be one last expect on the rect to ensure that Box 0 is back to where it started?

await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyUpEvent(modifierKey);
await tester.pumpAndSettle();

Copy link
Member

Choose a reason for hiding this comment

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

same here.

@gspencergoog gspencergoog merged commit 0190e40 into flutter:master Nov 26, 2019
@gspencergoog gspencergoog deleted the keyboard_scroll branch January 16, 2020 22:11
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 2, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: desktop Running on desktop framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for scrollables with keyboard bindings
4 participants