For my project I'm looking to implement a ScrollView that shows items as if you're browsing through a box of business cards. I based my current implementation on Albert Brand's article on Animated ScrollViews (after trying many other approaches).
However, the whole thing becomes very jittery now. Can anyone advise me how to smoothen the current implementation? Alternatively, does anyone have a tip how to get this behaviour in a different manner? Any solution should work in both iOS and Android.
This gif shows my current implementation including the jittering problem. It also should give a clear picture of what behaviour I'm after: screencapture of the ScrollView in iOS simulator
This is my current implementation:
import React from 'react'
import {
Animated,
Dimensions,
ScrollView,
StyleSheet,
Text,
View,
StatusBar,
} from 'react-native'
const SCREEN_HEIGHT = Dimensions.get('window').height
const yOffset = new Animated.Value(0)
const onScroll = Animated.event(
[{ nativeEvent: { contentOffset: { y: yOffset } } }],
)
function CardView(props: { children?: ReactElement<*> }) {
return (
<Animated.ScrollView
scrollEventThrottle={16}
onScroll={onScroll}
pagingEnabled
>
{props.children}
</Animated.ScrollView>
)
}
function Page(props: { children?: ReactElement<*>, index: 1 }) {
return (
<Animated.View style={[style.scrollPage]}>
{props.children}
</Animated.View>
)
}
function Card(props: { text: string, index: number }) {
return (
<Animated.View style={[style.card, marginTransform(props.index)]}>
<Text>
{props.text}
</Text>
</Animated.View>
)
}
function marginTransform(index: number) {
return {
marginTop: yOffset.interpolate({
inputRange: [
(index - 1) * SCREEN_HEIGHT,
index * SCREEN_HEIGHT,
(index + 1) * SCREEN_HEIGHT,
(index + 2) * SCREEN_HEIGHT,
(index + 3) * SCREEN_HEIGHT,
],
outputRange: [
-40,
80,
SCREEN_HEIGHT + 40,
2 * SCREEN_HEIGHT + 20,
3 * SCREEN_HEIGHT,
],
extrapolate: 'clamp',
}),
}
}
export default function App() {
return (
<CardView>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((i) => {
return(
<Page key={i}>
<Card text={`Card ${i}`} index={i}>
</Card>
</Page>
)
})}
</CardView>
)
}
const style = StyleSheet.create({
scrollPage: {
height: SCREEN_HEIGHT,
backgroundColor: 'transparent',
},
card: {
height: SCREEN_HEIGHT,
alignItems: 'center',
borderRadius: 4,
borderWidth: 1,
backgroundColor: '#F5FCFF',
}
})