Scroll into view more aggressively

This commit is contained in:
Dan Abramov
2024-12-01 19:16:24 +00:00
parent e4aa00e140
commit f3ae13407d
+16 -16
View File
@@ -28,6 +28,9 @@ export interface TabBarProps {
const ITEM_PADDING = 10 const ITEM_PADDING = 10
const CONTENT_PADDING = 6 const CONTENT_PADDING = 6
// How much of the previous/next item we're requiring
// when deciding whether to scroll into view on tap.
const OFFSCREEN_ITEM_WIDTH = 20
export function TabBar({ export function TabBar({
testID, testID,
@@ -65,6 +68,7 @@ export function TabBar({
const layout = layouts.get()[index] const layout = layouts.get()[index]
const availableSize = containerSize.get() - 2 * CONTENT_PADDING const availableSize = containerSize.get() - 2 * CONTENT_PADDING
if (!layout) { if (!layout) {
// Should not happen, but fall back to equal sizes.
const offsetPerPage = contentSize.get() - availableSize const offsetPerPage = contentSize.get() - availableSize
return (index / (itemsLength - 1)) * offsetPerPage return (index / (itemsLength - 1)) * offsetPerPage
} }
@@ -170,21 +174,18 @@ export function TabBar({
const onPressUIThread = useCallback( const onPressUIThread = useCallback(
(index: number) => { (index: number) => {
'worklet' 'worklet'
if (isSyncingScroll.get() === true) { const itemLayout = layouts.get()[index]
const progressDiff = index - dragProgress.get() if (!itemLayout) {
const offsetDiff = progressToOffset(progressDiff) // Should not happen.
let offset = scrollX.get() + offsetDiff return
const itemLayout = layouts.get()[index] }
if (itemLayout) { const leftEdge = itemLayout.x - OFFSCREEN_ITEM_WIDTH
if ( const rightEdge = itemLayout.x + itemLayout.width + OFFSCREEN_ITEM_WIDTH
itemLayout.x < offset || const scrollLeft = scrollX.get()
itemLayout.x + itemLayout.width > offset + containerSize.get() const scrollRight = scrollLeft + containerSize.get()
) { const scrollIntoView = leftEdge < scrollLeft || rightEdge > scrollRight
// If the proposed offset is still out of view, don't bother with if (isSyncingScroll.get() === true || scrollIntoView) {
// proportional scroll and ensure the target is scrolled into view. const offset = progressToOffset(index)
offset = progressToOffset(index)
}
}
scrollTo(scrollElRef, offset, 0, true) scrollTo(scrollElRef, offset, 0, true)
} }
isSyncingScroll.set(true) isSyncingScroll.set(true)
@@ -193,7 +194,6 @@ export function TabBar({
isSyncingScroll, isSyncingScroll,
scrollElRef, scrollElRef,
scrollX, scrollX,
dragProgress,
progressToOffset, progressToOffset,
containerSize, containerSize,
layouts, layouts,