Sync scroll to swipe properly
This commit is contained in:
@@ -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],
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user