-
-
Notifications
You must be signed in to change notification settings - Fork 817
FixedSizeList fixes for onItemsRendered & partially-visible items #274
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,12 +23,13 @@ const FixedSizeList = createListComponent({ | |
| // TODO Deprecate direction "horizontal" | ||
| const isHorizontal = direction === 'horizontal' || layout === 'horizontal'; | ||
| const size = (((isHorizontal ? width : height): any): number); | ||
| const maxOffset = Math.max( | ||
| const lastViewportOffset = Math.max( | ||
| 0, | ||
| Math.min( | ||
| itemCount * ((itemSize: any): number) - size, | ||
| index * ((itemSize: any): number) | ||
| ) | ||
| itemCount * ((itemSize: any): number) - size | ||
| ); | ||
| const maxOffset = Math.min( | ||
| lastViewportOffset, | ||
| index * ((itemSize: any): number) | ||
| ); | ||
| const minOffset = Math.max( | ||
| 0, | ||
|
|
@@ -51,14 +52,35 @@ const FixedSizeList = createListComponent({ | |
| return maxOffset; | ||
| case 'end': | ||
| return minOffset; | ||
| case 'center': | ||
| return Math.round(minOffset + (maxOffset - minOffset) / 2); | ||
| case 'center': { | ||
| // "Centered" offset is usually the average of the min and max | ||
| // offsets. But near the beginning or end of the list, this math | ||
| // doesn't produce the actual closest-to-center offset, so we | ||
| // override. | ||
| const centered = Math.round(minOffset + (maxOffset - minOffset) / 2); | ||
| if (centered < Math.ceil(size / 2)) { | ||
| return 0; // near the beginning | ||
| } else if (centered > lastViewportOffset + Math.floor(size / 2)) { | ||
| return lastViewportOffset; // near the end | ||
| } else { | ||
| return centered; | ||
| } | ||
| } | ||
| case 'auto': | ||
| default: | ||
| if (scrollOffset >= minOffset && scrollOffset <= maxOffset) { | ||
| return scrollOffset; | ||
| } else if (scrollOffset - minOffset < maxOffset - scrollOffset) { | ||
| return minOffset; | ||
| } else if (scrollOffset < minOffset) { | ||
| // For auto alignment, if size isn't an even multiple of itemSize, | ||
| // always put the partial item at the end of the viewport because it | ||
| // looks better than at the beginning. Exception: don't do this if the | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I understand the reasoning behind this added complexity. Why does it "look better"?
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I disagree with this change. Probably going to remove it. It breaks the specification of "auto" scroll behavior, by over-scrolling in the case when you're scrolling from a lower to higher index.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Imagine a list with I'm suggesting that It's something of a judgement call. I don't feel very strongly about this one way or the other, esp. because my current use of react-window doesn't trigger this case. If you take it out I won't be offended. ;-) BTW, I've been using the relatively-new CSS setting
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think I understood the suggestion just not the reasoning behind it 😄 thanks for elaborating~
Ah, that's interesting. I haven't played with the two yet. I can see how it might be a UX improvement!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep I've also had good results with It's amazing how much better browsers in general (and CSS in particular) have gotten in the last 5 years. The surface area is huge though-- hard to keep up with! |
||
| // viewport is already scrolled to the end. | ||
| const remainder = size % ((itemSize: any): number); | ||
| if (minOffset + remainder < lastViewportOffset) { | ||
| return minOffset + remainder; | ||
| } else { | ||
| return minOffset; | ||
| } | ||
| } else { | ||
| return maxOffset; | ||
| } | ||
|
|
@@ -83,14 +105,17 @@ const FixedSizeList = createListComponent({ | |
| const isHorizontal = direction === 'horizontal' || layout === 'horizontal'; | ||
| const offset = startIndex * ((itemSize: any): number); | ||
| const size = (((isHorizontal ? width : height): any): number); | ||
| // How far before the scrollOffset does the first visible item start? | ||
| // Will be zero if scrollOffset is an item boundary. | ||
| const startingPartialSize = scrollOffset - offset; | ||
| const visibleItems = Math.ceil( | ||
| (size + startingPartialSize) / ((itemSize: any): number) | ||
| ); | ||
| return Math.max( | ||
| 0, | ||
| Math.min( | ||
| itemCount - 1, | ||
| startIndex + | ||
| Math.floor( | ||
| (size + (scrollOffset - offset)) / ((itemSize: any): number) | ||
| ) | ||
| startIndex + visibleItems - 1 // -1 is because stop index is inclusive | ||
| ) | ||
| ); | ||
| }, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change looks good 👍