高速轮播的snap(2022-09-14)
ScrollView里有一对很有意思很酷炫的属性
snapToInterval
snapToAlignment
这两个属性的具体解释,请参考 snapToInterval 和 snapToAlignment
以下面这段代码为例(原始代码来自这里)
import React, { useRef } from "react";
import {
SafeAreaView,
ScrollView,
Text,
StyleSheet,
View,
ImageBackground,
Animated,
useWindowDimensions
} from "react-native";
const images = new Array(6).fill('https://images.unsplash.com/photo-1556740749-887f6717d7e4');
const App = () => {
const scrollX = useRef(new Animated.Value(0)).current;
const { width: windowWidth } = useWindowDimensions();
return (
<SafeAreaView style={styles.container}>
<View style={styles.scrollContainer}>
<ScrollView
horizontal={true}
pagingEnabled
showsHorizontalScrollIndicator={false}
onScroll={Animated.event([
{
nativeEvent: {
contentOffset: {
x: scrollX
}
}
}
])}
snapToInterval={windowWidth}
snapToAlignment='center'
scrollEventThrottle={1}
>
{images.map((image, imageIndex) => {
return (
<View
style={{ width: windowWidth, height: 250 }}
key={imageIndex}
>
<ImageBackground source={{ uri: image }} style={styles.card}>
<View style={styles.textContainer}>
<Text style={styles.infoText}>
{"Image - " + imageIndex}
</Text>
</View>
</ImageBackground>
</View>
);
})}
</ScrollView>
<View style={styles.indicatorContainer}>
{images.map((image, imageIndex) => {
const width = scrollX.interpolate({
inputRange: [
windowWidth * (imageIndex - 1),
windowWidth * imageIndex,
windowWidth * (imageIndex + 1)
],
outputRange: [8, 16, 8],
extrapolate: "clamp"
});
return (
<Animated.View
key={imageIndex}
style={[styles.normalDot, { width }]}
/>
);
})}
</View>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
scrollContainer: {
height: 300,
alignItems: "center",
justifyContent: "center"
},
card: {
flex: 1,
marginVertical: 4,
marginHorizontal: 16,
borderRadius: 5,
overflow: "hidden",
alignItems: "center",
justifyContent: "center"
},
textContainer: {
backgroundColor: "rgba(0,0,0, 0.7)",
paddingHorizontal: 24,
paddingVertical: 8,
borderRadius: 5
},
infoText: {
color: "white",
fontSize: 16,
fontWeight: "bold"
},
normalDot: {
height: 8,
width: 8,
borderRadius: 4,
backgroundColor: "silver",
marginHorizontal: 4
},
indicatorContainer: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center"
}
});
export default App;
当我在手机里运行时,我会看到一个6个图片的轮播图,每次手指左右滑动一下,不论速度是快还是慢,图片都是一张一张切换。当我把图片数量扩大10倍,变成60,再一张一张切换,就会觉得要过很久才能切换到最后一张图片。
const images = new Array(60).fill('https://images.unsplash.com/photo-1556740749-887f6717d7e4');
注:当你修改为60时,这段代码涉及到的动画部分的一些功能,就无法正常运行,但是这里只是为了说明sanp的那两个属性的效果,请忽略动画部分。
此时,我的记忆中出现了之前遇到的一些类似场景,在那些场景下,当我用手飞速滑动轮播图时,图片飞快的滚动起来,瞬间抵达非常靠后的一张图片。但是此时,不论我怎么滑动我的手指,轮播图还是不紧不慢的一张一张的翻动,完全不考虑到有60张图片在后面排队。
于是我加上了这两个属性
... ...
const { width: windowWidth } = useWindowDimensions();
... ...
<ScrollView
... ...
snapToInterval={windowWidth}
snapToAlignment='center'
... ...
>
一瞬间,轮播图飞速旋转起来啦,并且不会错位,每次都是正好是一图片居中,这就是这两个参数一起作用下的神奇效果。
这两个参数都是一起出现的,至少我查阅了git hub上近150个React Native的项目,只要是用到其中某一个属性的,必然伴随着另一个。