В этой статье демонстрируется простой подход к созданию анимации со скоростью 60 кадров в секунду для заголовка списка прокрутки (например, изображения), когда вы выполняете эффект отскока, прокручивая вверх в приложениях iOS.
Я буду использовать Expo, поскольку с его помощью легко начать работу с React Native и использовать react-native-reanimated для создания красивых и плавных анимаций:
Установите зависимости и запустите проект:
npm i expo-cli
expo init my-app
expo install react-native-reanimated
Создайте базовый макет для анимации:
export default function App() { return ( <View style={styles.container}> <Image style={styles.image} source={{ uri: 'http://picsum.photos/1000/1000' }} /> <ScrollView contentContainerStyle={{ flexGrow: 1 }}> <View style={styles.items}> {new Array(15).fill(0).map((_, index) => <View key={index} style={styles.item} />)} </View> </ScrollView> </View> ); }
const IMAGE_HEIGHT = 300;
const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#000', }, items: { paddingTop: IMAGE_HEIGHT, paddingHorizontal: 8, }, image: { ...StyleSheet.absoluteFillObject, top: 0, height: IMAGE_HEIGHT, width: '100%' }, title: { color: '#FFF' }, item: { backgroundColor: '#1C1C1C', height: 50, width: '100%', marginTop: 8, } });
Давайте рассмотрим код!
- Как видите, я использую
ScrollView
иImage
изreact-native-reanimated
для получения анимированных узлов. - Значение свойства
scrollEventThrottle
равно16
для узлаScrollView
для ограничения вызова событий. useValue
- хук для созданияAnimated.Value
.Animated.event
принимает массив сопоставлений и соответственно извлекает значения из каждого аргумента. В нашем случае мы извлекаемcontentOffset.y
и присваиваем егоscrollY
, поэтому значениеscrollY
на исходной стороне всегда совпадает сoffsetY
нашегоAnimated.ScrollView
.- Интерполяции
offsetY
изAnimated.ScrollView
дляAnimated.Image
:
translateY
нужен для перевода изображения вверх при прокрутке внизscale
масштабирует изображение при прокрутке.
export default function App() {
const scrollY = useValue(0)
return (
<View style={styles.container}>
<Animated.Image
style={{
...styles.image,
transform: [
{
translateY: interpolate(scrollY, {
inputRange: [0, IMAGE_WIDTH],
outputRange: [0, -IMAGE_WIDTH],
extrapolate: Extrapolate.CLAMP,
}),
scale: interpolate(scrollY, {
inputRange: [-IMAGE_WIDTH * 2, 0],
outputRange: [5, 1],
extrapolate: Extrapolate.CLAMP,
}),
},
],
}}
source={{ uri: 'http://picsum.photos/1000/1000' }}
/>
<Animated.ScrollView
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
{ useNativeDriver: true }
)}
contentContainerStyle={{ flexGrow: 1 }}
scrollEventThrottle={16}
>
<View style={styles.items}>
{new Array(15).fill(0).map((_, index) => <View key={index} style={styles.item} />)}
</View>
</Animated.ScrollView>
</View>
);
}
Эффект анимации будет таким:
Надеюсь, с тобой все хорошо. Удачного кодирования! 🎉