更新到
Expo SDK 52
后,轮播中的图像不再正确显示,经常出现裁剪或未对齐的情况,特别是对于纵向图像。此问题似乎源于新 SDK 版本中图像渲染或调整大小方式的变化。目标是通过确保所有图像完全适合轮播而没有任何裁剪或错位来解决此问题,但我在这样做时遇到了困难。 SDK的强制更新给我带来了很多问题。
代码
import * as React from "react";
import { Animated, View } from "react-native";
import { useSharedValue } from "react-native-reanimated";
import Carousel, {
ICarouselInstance,
Pagination,
} from "react-native-reanimated-carousel";
import { window } from "../features/favourites/constants";
const PAGE_WIDTH = window.width;
function Test({
images,
}: {
images: { original: string; thumbnail: string }[];
}) {
const progress = useSharedValue<number>(0);
const ref = React.useRef<ICarouselInstance>(null);
const onPressPagination = (index: number) => {
ref.current?.scrollTo({
count: index - progress.value,
animated: true,
});
};
return (
<View style={{ flex: 1 }}>
<Carousel
ref={ref}
vertical={false}
width={PAGE_WIDTH}
height={PAGE_WIDTH * 0.6}
loop
pagingEnabled
snapEnabled
autoPlay
autoPlayInterval={2500}
onProgressChange={(_, progressValue) => {
progress.value = progressValue;
}}
mode="parallax"
modeConfig={{
parallaxScrollingScale: 0.9,
parallaxScrollingOffset: 50,
}}
data={images}
renderItem={({ index }) => (
<View
key={index}
style={{
backgroundColor: "#fff",
borderRadius: 10,
width: PAGE_WIDTH / 1,
height: PAGE_WIDTH / 1.8,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.34,
shadowRadius: 10.32,
elevation: 16,
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Image
source={{ uri: images[index].original }}
style={{
width: PAGE_WIDTH / 1,
height: PAGE_WIDTH / 1.8,
borderRadius: 10,
justifyContent: "center",
alignItems: "center",
}}
resizeMode={"cover"}
/>
</View>
)}
/>
{Pagination && Pagination.Basic && (
<Pagination.Basic
progress={progress}
data={images}
dotStyle={{ backgroundColor: "rgba(0,0,0,0.2)" }}
containerStyle={{ gap: 5, marginBottom: 10 }}
onPress={onPressPagination}
/>
)}
</View>
);
}
export default Test;
我也尝试过
react-native-snap-carousel
,仍然是同样的问题。
这是package.json
"react-native-reanimated": "^3.16.5",
"react-native-reanimated-carousel": "^4.0.0-canary.20",
"react-native": "0.76.5",
我审查了代码的某些部分,发现一些 styling 属性可以更改,特别是 Animated.Image 中的属性,因为 Image 类似乎需要 root 类参数 的尺寸,这些可以在样式属性之外给出,也可以更改一些其他尺寸值,请查看下面修改行的注释:
return (
<View style={{ flex: 1 }}>
<Carousel
ref={ref}
vertical={false}
width={PAGE_WIDTH}
height={PAGE_WIDTH} //*0.6 may resize the inner Image to the 60% of the size
loop
pagingEnabled
snapEnabled
autoPlay
autoPlayInterval={2500}
onProgressChange={(_, progressValue) => {
progress.value = progressValue;
}}
mode="parallax"
modeConfig={{
parallaxScrollingScale: 0.9,
parallaxScrollingOffset: 50,
}}
data={images}
renderItem={({ index }) => (
<View
key={index}
style={{
backgroundColor: "#fff",
borderRadius: 10,
width: 'auto', //changing this to auto may help to fit entire width of screen
height: PAGE_WIDTH, // this PAGE_WIDTH / 1.8 tells the child view of component to be 180% of screen width which if landscape it may not be desired
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.34,
shadowRadius: 10.32,
elevation: 5,
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Image
source={{ uri: images[index].original }}
width={PAGE_WIDTH}
height={PAGE_WIDTH / 1.8}
style={{
borderRadius: 10,
justifyContent: "center",
alignItems: "center",
}}
resizeMode={"cover"}
/>
</View>
)}
/>
{Pagination && Pagination.Basic && (
<Pagination.Basic
progress={progress}
data={images}
dotStyle={{ backgroundColor: "rgba(0,0,0,0.2)" }}
containerStyle={{ gap: 5, marginBottom: 10 }}
onPress={onPressPagination}
/>
)}
</View>
);
}
export default Test;
模拟 Carousel 功能的另一种方法如下:
import { Dimensions, ScrollView } from 'react-native';
const { height: SCREEN_HEIGHT, width: SCREEN_WIDTH } = Dimensions.get('window');
const scrollViewRef = useRef(null);
const carouselItems = [
{ icon: faDollar, label: "Money" },
{ icon: faLanguage, label: "Language" },
{ icon: faToolbox, label: "Tools" },
];
const handleScroll = (event) => {
const contentOffsetX = event.nativeEvent.contentOffset.x;
const index = Math.floor(contentOffsetX / SCREEN_WIDTH);
setCurrentIndex(index);
};
提供flexGrow的样式:1,如下:
contentContainer: {
flexGrow: 1,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 70, // Adjust padding as needed
},
在这里您可以为轮播添加类似的动画行为:
<ScrollView
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onScroll={handleScroll}
scrollEventThrottle={16}
ref={scrollViewRef}
snapToAlignment="center"
decelerationRate="fast"
contentContainerStyle={styles.contentContainer}
>
{carouselItems.map((item, index) => renderItem(item, index))}
</ScrollView>
这是渲染项功能:
const renderItem = (item, index) => {
let navigateTo;
switch (item.label) {
case "Money":
navigateTo = 'ScreenPage1'; //another ScreenPage1.tsx
break;
case "Language":
navigateTo = 'ScreenPage2'; //another ScreenPage2.tsx
break;
case "Tools":
navigateTo = 'ScreenPage3'; //another ScreenPage3.tsx
break;
default:
navigateTo = null;
}