Sync scroll to swipe properly

This commit is contained in:
Dan Abramov
2024-11-29 23:44:46 +00:00
parent 6d134229d6
commit 505e3adc77
2 changed files with 24 additions and 26 deletions
+18 -7
View File
@@ -76,18 +76,19 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
[pagerView],
)
const pendingPage = useSharedValue(selectedPage)
const dragPage = useSharedValue(selectedPage)
const dragProgress = useSharedValue(0)
const dragState = useSharedValue<'idle' | 'settling' | 'dragging'>('idle')
const handlePageScroll = usePagerHandlers(
// These events don't fire exactly the same way on Android and iOS.
// In these handlers we normalize the behavior to have consistent output values.
{
onPageScroll(e: PagerViewOnPageScrollEventData) {
'worklet'
let {position, offset} = e
if (position === dragPage.value) {
dragProgress.set(offset)
} else {
const offsetFromPage = position + offset - dragPage.value
if (offset !== 0) {
const offsetFromPage = offset + (position - dragPage.value)
dragProgress.set(offsetFromPage)
}
},
@@ -95,12 +96,22 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
'worklet'
dragState.set(e.pageScrollState)
parentOnPageScrollStateChanged?.(e.pageScrollState)
if (e.pageScrollState === 'idle') {
const page = pendingPage.get()
dragPage.set(page)
dragProgress.set(0)
runOnJS(onPageSelectedJSThread)(page)
}
},
onPageSelected(e: PagerViewOnPageSelectedEventData) {
'worklet'
dragPage.set(e.position)
dragProgress.set(0)
runOnJS(onPageSelectedJSThread)(e.position)
pendingPage.set(e.position)
if (dragState.value === 'idle') {
const page = e.position
dragPage.set(page)
dragProgress.set(0)
runOnJS(onPageSelectedJSThread)(e.position)
}
},
},
[parentOnPageScrollStateChanged],
+6 -19
View File
@@ -4,7 +4,6 @@ import Animated, {
scrollTo,
useAnimatedReaction,
useAnimatedRef,
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated'
@@ -47,24 +46,17 @@ export function TabBar({
const {dragPage, dragProgress} = dragGesture
useAnimatedReaction(
() => dragPage.get(),
(page, prevPage) => {
if (page !== prevPage) {
() => dragPage.get() + dragProgress.get(),
(next, prev) => {
if (next !== prev) {
const offsetPerPage = contentSize.get() - containerSize.get()
const offset = (dragPage.get() / (itemsLength - 1)) * offsetPerPage
const offset = (next / (itemsLength - 1)) * offsetPerPage
scrollTo(scrollElRef, offset, 0, false)
return
}
},
)
const contentStyle = useAnimatedStyle(() => {
const offsetPerPage = contentSize.get() - containerSize.get()
const offset = (dragProgress.get() / (itemsLength - 1)) * offsetPerPage
return {
transform: [{translateX: -offset}],
}
})
return (
<View
testID={testID}
@@ -83,12 +75,7 @@ export function TabBar({
onLayout={e => {
contentSize.set(e.nativeEvent.layout.width)
}}
style={[
contentStyle,
{
flexDirection: 'row',
},
]}>
style={{flexDirection: 'row'}}>
{items.map((item, i) => {
return (
<TabBarItem