Sync scroll to swipe properly
This commit is contained in:
@@ -76,18 +76,19 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
|
|||||||
[pagerView],
|
[pagerView],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const pendingPage = useSharedValue(selectedPage)
|
||||||
const dragPage = useSharedValue(selectedPage)
|
const dragPage = useSharedValue(selectedPage)
|
||||||
const dragProgress = useSharedValue(0)
|
const dragProgress = useSharedValue(0)
|
||||||
const dragState = useSharedValue<'idle' | 'settling' | 'dragging'>('idle')
|
const dragState = useSharedValue<'idle' | 'settling' | 'dragging'>('idle')
|
||||||
const handlePageScroll = usePagerHandlers(
|
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) {
|
onPageScroll(e: PagerViewOnPageScrollEventData) {
|
||||||
'worklet'
|
'worklet'
|
||||||
let {position, offset} = e
|
let {position, offset} = e
|
||||||
if (position === dragPage.value) {
|
if (offset !== 0) {
|
||||||
dragProgress.set(offset)
|
const offsetFromPage = offset + (position - dragPage.value)
|
||||||
} else {
|
|
||||||
const offsetFromPage = position + offset - dragPage.value
|
|
||||||
dragProgress.set(offsetFromPage)
|
dragProgress.set(offsetFromPage)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -95,12 +96,22 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
|
|||||||
'worklet'
|
'worklet'
|
||||||
dragState.set(e.pageScrollState)
|
dragState.set(e.pageScrollState)
|
||||||
parentOnPageScrollStateChanged?.(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) {
|
onPageSelected(e: PagerViewOnPageSelectedEventData) {
|
||||||
'worklet'
|
'worklet'
|
||||||
dragPage.set(e.position)
|
pendingPage.set(e.position)
|
||||||
dragProgress.set(0)
|
if (dragState.value === 'idle') {
|
||||||
runOnJS(onPageSelectedJSThread)(e.position)
|
const page = e.position
|
||||||
|
dragPage.set(page)
|
||||||
|
dragProgress.set(0)
|
||||||
|
runOnJS(onPageSelectedJSThread)(e.position)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[parentOnPageScrollStateChanged],
|
[parentOnPageScrollStateChanged],
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import Animated, {
|
|||||||
scrollTo,
|
scrollTo,
|
||||||
useAnimatedReaction,
|
useAnimatedReaction,
|
||||||
useAnimatedRef,
|
useAnimatedRef,
|
||||||
useAnimatedStyle,
|
|
||||||
useSharedValue,
|
useSharedValue,
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
|
|
||||||
@@ -47,24 +46,17 @@ export function TabBar({
|
|||||||
const {dragPage, dragProgress} = dragGesture
|
const {dragPage, dragProgress} = dragGesture
|
||||||
|
|
||||||
useAnimatedReaction(
|
useAnimatedReaction(
|
||||||
() => dragPage.get(),
|
() => dragPage.get() + dragProgress.get(),
|
||||||
(page, prevPage) => {
|
(next, prev) => {
|
||||||
if (page !== prevPage) {
|
if (next !== prev) {
|
||||||
const offsetPerPage = contentSize.get() - containerSize.get()
|
const offsetPerPage = contentSize.get() - containerSize.get()
|
||||||
const offset = (dragPage.get() / (itemsLength - 1)) * offsetPerPage
|
const offset = (next / (itemsLength - 1)) * offsetPerPage
|
||||||
scrollTo(scrollElRef, offset, 0, false)
|
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 (
|
return (
|
||||||
<View
|
<View
|
||||||
testID={testID}
|
testID={testID}
|
||||||
@@ -83,12 +75,7 @@ export function TabBar({
|
|||||||
onLayout={e => {
|
onLayout={e => {
|
||||||
contentSize.set(e.nativeEvent.layout.width)
|
contentSize.set(e.nativeEvent.layout.width)
|
||||||
}}
|
}}
|
||||||
style={[
|
style={{flexDirection: 'row'}}>
|
||||||
contentStyle,
|
|
||||||
{
|
|
||||||
flexDirection: 'row',
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
{items.map((item, i) => {
|
{items.map((item, i) => {
|
||||||
return (
|
return (
|
||||||
<TabBarItem
|
<TabBarItem
|
||||||
|
|||||||
Reference in New Issue
Block a user