iPhone 11
iOS: 14.4
Example app
When swiping on Android back and fort the position stays the same and the offset is changing only.
Example:
[Wed Apr 14 2021 08:27:02.615] LOG Position: 1 Offset: 0.023148147389292717 // swiping left
[Wed Apr 14 2021 08:27:02.787] LOG Position: 1 Offset: 0.02500000037252903 // swiping left
[Wed Apr 14 2021 08:27:02.820] LOG Position: 1 Offset: 0.02777777798473835 // swiping left
[Wed Apr 14 2021 08:27:05.399] LOG Position: 1 Offset: 0.02500000037252903 // swiping right
[Wed Apr 14 2021 08:27:05.433] LOG Position: 1 Offset: 0.023148147389292717 // swiping right
When swiping on iOS back and fort both the position and the offset is changing.
Example:
[Wed Apr 14 2021 08:30:40.408] LOG Position: 1 Offset: 0.047101449221372604 // swiping left
[Wed Apr 14 2021 08:30:40.435] LOG Position: 1 Offset: 0.050724636763334274 // swiping left
[Wed Apr 14 2021 08:30:41.305] LOG Position: 0 Offset: 0.9504830837249756 // swiping right
[Wed Apr 14 2021 08:30:41.326] LOG Position: 0 Offset: 0.9528985619544983 // swiping right
[Wed Apr 14 2021 08:30:41.345] LOG Position: 0 Offset: 0.95652174949646 // swiping right
This behaviour messes up the animation. iOS should behave like android
Heres a video that shows the bug, just watch the bottom paginating circles.
Just run the example app of this repo.
Start swiping left/right then change the direction.
Same here, swipe back giving inconsistent position on iOS. I've tried change the version since 5.1.0 but always got the same behaviour.
Hi!
I think I am having the same problem here https://github.com/callstack/react-native-pager-view/issues/355
Did you have any workarounds?
Original author: @punksta
"react-native-pager-view": "5.1.8",
I am trying to implement page indicator when you swipe pages in the pager using Animated, connected to onPageScroll.
add the following listener to your pager and see console log.
onPageScroll={Animated.event(
[
{
nativeEvent: {
position: pageScrollPosition,
offset: pageScrollOffset
}
}
],
{
listener: event => {
event.persist()
console.log(event.nativeEvent)
},
useNativeDriver: false
}
)}
I start dragging to right, I don't release your finger and change direction of the drag to back left.
{"offset": 0, "position": 0}
LOG {"offset": 0.011111111380159855, "position": 0}
LOG {"offset": 0.021367521956562996, "position": 0}
LOG {"offset": 0.03076923079788685, "position": 0}
LOG {"offset": 0.04017094150185585, "position": 0}
...
LOG {"offset": 0.26923078298568726, "position": 0}
LOG {"offset": 0.27008548378944397, "position": 0}
LOG {"offset": 0.7316238880157471, "position": -1}
LOG {"offset": 0.7333333492279053, "position": -1}
LOG {"offset": 0.7350426912307739, "position": -1}
LOG {"offset": 0.7367521524429321, "position": -1}
On UI it results in jumping of the page indicator between pages.
The same behavior arises for other pages too.
position should stay on "position": 0 and offset should decrease from 0.2 to 0.
```
import React from 'react'
import { Animated, Dimensions, Pressable, StyleSheet, View } from 'react-native'
import ViewPager from 'react-native-pager-view'
import { Text } from 'react-native'
const AnimatedViewPager = Animated.createAnimatedComponent(ViewPager)
export const SwapMealScreen: React.FC<{}> = React.memo(() => {
const ref = React.useRef
const pageScrollPosition = React.useMemo(() => new Animated.Value(0), [])
const pageScrollOffset = React.useMemo(() => new Animated.Value(0), [])
const [pageIndex, setPageIndex] = React.useState(0)
const pageIndicatorTransactionX = Animated.add(
Animated.multiply(pageScrollPosition, Dimensions.get('window').width / 3),
Animated.multiply(pageScrollOffset, Dimensions.get('window').width / 3)
)
return (
<>
const isSelected = index === pageIndex
return (
<Pressable
collapsable={false}
onPress={() => {
jumpToPage(index)
setImmediate(() => {
ref.current?.setPage?.(index)
})
}}
key={pageName}
style={styles.tabContainer}
>
<Text
style={{
fontSize: 32,
color: isSelected ? '#090' : '#000'
}}
>
{pageName}
</Text>
</Pressable>
)
})}
<Animated.View
style={[
styles.indicator,
{
transform: [
{
translateX: pageIndicatorTransactionX
}
]
}
]}
/>
</View>
<AnimatedViewPager
ref={ref}
transitionStyle={'scroll'}
overScrollMode={'always'}
initialPage={0}
onPageScroll={Animated.event(
[
{
nativeEvent: {
position: pageScrollPosition,
offset: pageScrollOffset
}
}
],
{
listener: event => {
event.persist()
console.log(event.nativeEvent)
},
useNativeDriver: false
}
)}
onPageSelected={event => setPageIndex(event.nativeEvent.position)}
style={styles.pager}
>
{[1, 2, 3].map(page => {
return (
<View
style={{
backgroundColor: `rgba(0, 0, 0, ${(page - 1) * 0.5})`,
width: Dimensions.get('window').width,
height: '100%'
}}
/>
)
})}
</AnimatedViewPager>
</>
)
})
const styles = StyleSheet.create({
tabContainer: {
flex: 1,
paddingBottom: 8,
marginBottom: 6,
paddingHorizontal: 8,
marginHorizontal: 16
},
indicator: {
left: 24,
position: 'absolute',
bottom: 0,
height: 3,
width: 30,
backgroundColor: 'green'
},
titles: {
marginTop: 60,
flexDirection: 'row'
},
pager: {
overflow: 'visible',
flex: 1
}
})
```
Currently onPageScroll returns position and positionOffset value. I was trying to implement it on iOS , but it seems like does not work very well. There are two options to fix it:
positionOffsetPixels (BREAKING CHANGE) doc, but in this case you need to compare, if both values are the same on iOS and Androidposition should stay the same when changing directions, however offset should increase or decrease until 1 or 0 and only then change the position.
positionshould stay the same when changing directions, howeveroffsetshould increase or decrease until 1 or 0 and only then change theposition.
Here you can find all calculations https://github.com/callstack/react-native-pager-view/blob/master/ios/ReactNativePageView.m#L374.
The latest release introduced a new issue, over-dragging the first page to the left, move the pagination and the onPageScroll event to the oposite direction. [see attached video]
Is there a way to fix this?
https://user-images.githubusercontent.com/2472594/119741301-0de70280-be4b-11eb-986b-a5d205cb690b.mov
I see it. On Android it just ignores the overscroll and returns 0 for offset.
I will create another PR for that soon.
@troZee
What do you think about setting overdrag prop to false by default?
For the bug mentioned by @elkinjosetm a possible fix would be enabling negative offset or position, but then #310 would come back.
@troZee
What do you think about settingoverdragprop tofalseby default?For the bug mentioned by @elkinjosetm a possible fix would be enabling negative
offsetorposition, but then #310 would come back.
I think, we can set this prop to false by default
Yeah, Android doesn't have overscroll, so that's why there is no issue there. Thanks, I'm looking forward for that release.
I would keep the overdrag enabled by default on iOS, because that's a default behaviour on iOS.
I theory, returning only position -1 on the onPageScroll when is dragging to the left from the first page makes sense, since dragging to the any other page, from any page different than 0, will return the "upcoming" position.
I noticed that next code works good and on iOS on the current PagerView version (5.2.1) (it worked bad on some previous version).
```
const scrollAnimatedValue = useMemo(
() => Animated.add(positionAnimatedValue, offsetAnimatedValue),
[positionAnimatedValue, offsetAnimatedValue],
);
const onScroll = useMemo(() => Animated.event(
[{
nativeEvent: {
position: positionAnimatedValue,
offset: offsetAnimatedValue,
},
}],
{ useNativeDriver: true },
), [positionAnimatedValue, offsetAnimatedValue]);
```
So I switched from ScrollView on iOS to PagerView.
Ofcourse I enabled overdrag.
But unfortunately now I see that left overdrag works wrong. scrollAnimatedValue should be negative when overdrag to the left.
Have to go back to ScrollView on iOS until it will fixed. :(
Most helpful comment
I would keep the overdrag enabled by default on iOS, because that's a default behaviour on iOS.
I theory, returning only position -1 on the onPageScroll when is dragging to the left from the first page makes sense, since dragging to the any other page, from any page different than 0, will return the "upcoming" position.