Skip to content

Prevent dropdown menu's scroll offset from going negative#22235

Merged
mklim merged 2 commits intoflutter:masterfrom
mklim:dropdown_scroll
Sep 26, 2018
Merged

Prevent dropdown menu's scroll offset from going negative#22235
mklim merged 2 commits intoflutter:masterfrom
mklim:dropdown_scroll

Conversation

@mklim
Copy link
Copy Markdown
Contributor

@mklim mklim commented Sep 24, 2018

Before the offset was adjusted by - (buttonTop - menuTop), which meant
that with no item selected the offset would actually be a negative
number. In long lists that would result in the the dropdown scrolling to
the very last item in the list. Changed to be the selectedItemOffset
directly instead, since the extra margin seemed unnecessary.

Fixes #15346

@mklim
Copy link
Copy Markdown
Contributor Author

mklim commented Sep 24, 2018

@HansMuller I dug through the history a bit but didn't see the reasoning behind - (buttonTop - menuTop). From what I can tell it always computes a negative value, but maybe there's a case where that offset is needed that I'm not seeing? So far it looks like all the tests are passing with it removed still.

@HansMuller
Copy link
Copy Markdown
Contributor

HansMuller commented Sep 25, 2018

@mklim - the overall idea is to have the menu appear with the selected item lined up with (itself) the dropdown menu button's value. Forgetting scrolling for the moment: if the menu contains 4 items [A, B, C, D] the selected item is C, the dropdown looks like "Hello: C v", and when the menu pops up it looks like:

      A
      B 
Hello C
      D

As you can see, the top of the menu is negative relative to the top of the dropdown button.

Things get more complicated when it's also necessary to scroll the selected item into view of course. LIkewise if the dropdown menu is near enough to an edge (edges) to prevent positioning it exactly where we want it.

@mklim
Copy link
Copy Markdown
Contributor Author

mklim commented Sep 25, 2018

Thanks, makes sense. I'll add a test for that and rework this to make sure it still handles that case.

@mklim mklim removed the request for review from HansMuller September 25, 2018 16:55
@mklim mklim changed the title Set dropdown menu offset to equal selected item Prevent dropdown menu offset from going negative Sep 25, 2018
@mklim mklim requested a review from HansMuller September 25, 2018 17:53
@mklim
Copy link
Copy Markdown
Contributor Author

mklim commented Sep 25, 2018

Updated.

@HansMuller HansMuller changed the title Prevent dropdown menu offset from going negative Prevent dropdown menu's scroll offset from going negative Sep 26, 2018
Copy link
Copy Markdown
Contributor

@HansMuller HansMuller left a comment

Choose a reason for hiding this comment

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

This all looks good. I'd just like to get to the bottom of the attached assertions. Maybe we're trying to determine if tester.renderObject is turning up scrollable child that's no longer visible? Seems like that should be checked with expect, not assert(). And not by checking the attached property, but by checking that it's within the scrollable's viewport.

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.

This is OK, but it seems like an odd way to say:
math.max(0.0, selectedItemOffset - (buttonTop - menuTop))

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.

We typically only use => for one-liners that return a value.

Why not just put the buildFrame() call in-line?

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.

tester.renderObject<RenderBox>(...)

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.

await tester.pumpAndSettle()

Comment thread packages/flutter/test/material/dropdown_test.dart Outdated
Comment thread packages/flutter/test/material/dropdown_test.dart Outdated
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.

As before. Typically we don't add a level of indirection like this.

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.

Why are we asserting attached here and elsewhere? I don't believe WidgetTester.renderObject will succeed for an unattached renderer.

... I see, these assertions appear through this file, but not anywhere else (in fact I appear to responsible for a few of them).

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.

await tester.pumpAndSettle()

Michael Klimushyn added 2 commits September 26, 2018 10:53
In long lists this resulted in the dropdown scrolling to the very last
item in its list. Now clamping the value at `0.0`. Added a test to
verify that the selected item aligns with the button to test the offset.

Fixes #15346
@mklim
Copy link
Copy Markdown
Contributor Author

mklim commented Sep 26, 2018

Thanks for the review! This patch looks much cleaner now.

I'd just like to get to the bottom of the attached assertions.

They definitely weren't necessary for the test cases I added, I was just following the pattern I saw in other cases in this file. I assumed that it was common or best practice to assert that elements exist before acting on them since I saw it in other test cases. For my cases the last expect()s are checking everything that I need to actually verify. Not sure why the other test cases had them originally though, that is probably worth following up on.

Copy link
Copy Markdown
Contributor

@HansMuller HansMuller left a comment

Choose a reason for hiding this comment

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

LGTM

Eventually we should get to the bottom of the attached assertions in the rest of dropdown_test.dart. This PR looks good without them :-).

@gspencergoog
Copy link
Copy Markdown
Contributor

@fkorotkov, why is there still one GitHub check status that says it hasn't completed, when Cirrus says it has? It looks like GitHub is listing tests-windows status three times in this PR.

@fkorotkov
Copy link
Copy Markdown
Contributor

@gspencergoog there are two of them for the same task! One passed and one reported as still queued Looking into it.

@mklim
Copy link
Copy Markdown
Contributor Author

mklim commented Sep 26, 2018

@fkorotkov Thanks! I just recently tried restarting the task, if that makes a difference. The new run from that is https://cirrus-ci.com/task/5629948521873408.

@mklim mklim merged commit 020fd59 into flutter:master Sep 26, 2018
@mklim mklim deleted the dropdown_scroll branch September 26, 2018 21:28
if (preferredMenuHeight > maxMenuHeight)
scrollOffset = selectedItemOffset - (buttonTop - menuTop);
final double scrollOffset = (preferredMenuHeight > maxMenuHeight) ?
math.max(0.0, selectedItemOffset - (buttonTop - menuTop)) : 0.0;
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.

what i find weird about this approach is that it's asymmetrical. Why do we clamp at zero but not at some equivalent large offset?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I never saw a situation where selectedItemOffset - (buttonTop - menuTop) produced values that were incorrectly large, so I didn't see a need for it.

In my testing it looked like this did correctly calculate an offset for all items after the first one. It perfectly aligned them with the dropdown button itself if there was room to scroll to them. But it was consistently setting a negative value for when either nothing or the first item in a list was selected. In short lists that doesn't matter since there's no room to scroll, but as soon as there was a scrollbar then it was wrapping around to the bottom of the list to match the negative scrollOffset.

@jslavitz's fix in #22594 looks more robust to me. If the problem is with the variables in this calculation, updating that makes more sense than clamping off known incorrect bounds.

@jslavitz jslavitz self-assigned this Oct 3, 2018
@jslavitz
Copy link
Copy Markdown
Contributor

jslavitz commented Oct 3, 2018

Hey! I've got a fix here: #22594 that I think makes sense.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DropdownButton with long list scroll to end of list

7 participants