如何在 React Native 中使用 flatlist 实现图像旋转?
how to implement the image rotary using flatlist in react native?
我正在尝试完成垂直旋转木马,如下图所示。我对第二个屏幕感到震惊,当用户从底部到顶部滚动数据时,内容和图像都会发生变化,反之亦然,如何实现这一点?期待您的帮助?enter image description here
我提供了一个小吃示例,它与您想要的大部分相似。可以使用reanimated、Flatlist实现动画:
代码:
import * as React from 'react';
import { Text, View, StyleSheet, FlatList, Dimensions } from 'react-native';
import Constants from 'expo-constants';
import Animated, {
useSharedValue,
useAnimatedScrollHandler,
useAnimatedStyle,
interpolate,
Extrapolate,
} from 'react-native-reanimated';
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const { width, height } = Dimensions.get('window');
const bottomHeight = height - 150 - 30 - Constants.statusBarHeight;
const data = [
{
title: 'data1',
image:
'https://assets.website-files.com/5f204aba8e0f187e7fb85a87/5f210a533185e7434d9efcab_hero%20img.jpg',
},
{
title: 'data2',
image:
'https://www.whoa.in/201604-Whoa/10-alone-broken-image-mobile-wallpaper-hd-image.jpg',
},
{
title: 'data3',
image:
'https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
},
{
title: 'data4',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTntlma5HASL0HAM-KiC01A-JX4MxKousAA6A&usqp=CAU',
},
];
const ImageContent = ({ image, scrollValue, index }) => {
const animatedStyle = useAnimatedStyle(() => {
const inputRange = [index * bottomHeight, (index + 1) * bottomHeight];
const translateY = interpolate(
scrollValue.value,
inputRange,
[0, -150],
Extrapolate.CLAMP
);
return {
transform: [{ translateY }],
};
});
return (
<Animated.Image
source={{ uri: image }}
style={[styles.image, { zIndex: data.length - index }, animatedStyle]}
resizeMode="cover"
/>
);
};
const TopPart = React.memo(({ scrollValue }) => {
return (
<View style={styles.topPartContainer}>
{data.map(({ image }, index) => (
<ImageContent {...{ scrollValue, image, index }} />
))}
</View>
);
});
const Item = ({ item, index }) => {
return (
<View
style={[
styles.item,
]}>
<Text style={{ color: 'red' }}>{item.title}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
topPartContainer: {
width: 150,
height: 150,
borderRadius: 75,
alignSelf: 'center',
overflow: 'hidden',
},
image: {
...StyleSheet.absoluteFillObject,
backgroundColor: '#fff',
borderRadius: 75,
},
item: {
width,
backgroundColor: '#fff',
justifyContent: 'center',
alignItems: 'center',
height: bottomHeight,
},
});
function App() {
const scrollValue = useSharedValue(0);
const handler = useAnimatedScrollHandler((event) => {
scrollValue.value = event.contentOffset.y;
});
return (
<View style={styles.container}>
<TopPart {...{ scrollValue }} />
<View style={{ flex: 1, paddingTop: 30, height: bottomHeight }}>
<AnimatedFlatList
contentContainerStyle={{ height: data.length * bottomHeight }}
showsVerticalScrollIndicator={false}
onScroll={handler}
scrollEventThrottle={16}
data={data}
pagingEnabled
keyExtractor={(item) => item.title}
renderItem={({ item, index }) => <Item {...{ item, index }} />}
/>
</View>
</View>
);
}
我正在尝试完成垂直旋转木马,如下图所示。我对第二个屏幕感到震惊,当用户从底部到顶部滚动数据时,内容和图像都会发生变化,反之亦然,如何实现这一点?期待您的帮助?enter image description here
我提供了一个小吃示例,它与您想要的大部分相似。可以使用reanimated、Flatlist实现动画:
代码:
import * as React from 'react';
import { Text, View, StyleSheet, FlatList, Dimensions } from 'react-native';
import Constants from 'expo-constants';
import Animated, {
useSharedValue,
useAnimatedScrollHandler,
useAnimatedStyle,
interpolate,
Extrapolate,
} from 'react-native-reanimated';
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const { width, height } = Dimensions.get('window');
const bottomHeight = height - 150 - 30 - Constants.statusBarHeight;
const data = [
{
title: 'data1',
image:
'https://assets.website-files.com/5f204aba8e0f187e7fb85a87/5f210a533185e7434d9efcab_hero%20img.jpg',
},
{
title: 'data2',
image:
'https://www.whoa.in/201604-Whoa/10-alone-broken-image-mobile-wallpaper-hd-image.jpg',
},
{
title: 'data3',
image:
'https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
},
{
title: 'data4',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTntlma5HASL0HAM-KiC01A-JX4MxKousAA6A&usqp=CAU',
},
];
const ImageContent = ({ image, scrollValue, index }) => {
const animatedStyle = useAnimatedStyle(() => {
const inputRange = [index * bottomHeight, (index + 1) * bottomHeight];
const translateY = interpolate(
scrollValue.value,
inputRange,
[0, -150],
Extrapolate.CLAMP
);
return {
transform: [{ translateY }],
};
});
return (
<Animated.Image
source={{ uri: image }}
style={[styles.image, { zIndex: data.length - index }, animatedStyle]}
resizeMode="cover"
/>
);
};
const TopPart = React.memo(({ scrollValue }) => {
return (
<View style={styles.topPartContainer}>
{data.map(({ image }, index) => (
<ImageContent {...{ scrollValue, image, index }} />
))}
</View>
);
});
const Item = ({ item, index }) => {
return (
<View
style={[
styles.item,
]}>
<Text style={{ color: 'red' }}>{item.title}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
topPartContainer: {
width: 150,
height: 150,
borderRadius: 75,
alignSelf: 'center',
overflow: 'hidden',
},
image: {
...StyleSheet.absoluteFillObject,
backgroundColor: '#fff',
borderRadius: 75,
},
item: {
width,
backgroundColor: '#fff',
justifyContent: 'center',
alignItems: 'center',
height: bottomHeight,
},
});
function App() {
const scrollValue = useSharedValue(0);
const handler = useAnimatedScrollHandler((event) => {
scrollValue.value = event.contentOffset.y;
});
return (
<View style={styles.container}>
<TopPart {...{ scrollValue }} />
<View style={{ flex: 1, paddingTop: 30, height: bottomHeight }}>
<AnimatedFlatList
contentContainerStyle={{ height: data.length * bottomHeight }}
showsVerticalScrollIndicator={false}
onScroll={handler}
scrollEventThrottle={16}
data={data}
pagingEnabled
keyExtractor={(item) => item.title}
renderItem={({ item, index }) => <Item {...{ item, index }} />}
/>
</View>
</View>
);
}