我最初使用setInterval()
来制作循环图像背景,方法是有两个图像,一个从x:0
开始,另一个从x: imageWidth
开始,然后按以下方式更新它们:
_updateBackgroundImage = () => {
this.setState({
background1Left: this.state.background1Left > (-this.backgroundImageWidth) ? this.state.background1Left-3 : this.backgroundImageWidth,
background2Left: this.state.background2Left > (-this.backgroundImageWidth) ? this.state.background2Left-3 : this.backgroundImageWidth,
})
}
它工作得很好,但setInterval()
导致与在线库中的另一个组件发生冲突,所以我改用Animated
API 并具有以下代码:
this.translateValue = new Animated.Value(0)
translate() {
this.translateValue.setValue(0)
Animated.timing(
this.translateValue,
{
toValue: 1,
duration: 14000,
easing: Easing.linear
}
).start(()=>this.translate())
}
const translateBackgroundImage1 = this.translateValue.interpolate({ inputRange: [0, 1], outputRange: [0, -this.backgroundImageWidth] }) const translateBackgroundImage2 = this.translateValue.interpolate({ inputRange: [0, 1], outputRange: [this.backgroundImageWidth, -this.backgroundImageWidth] }) return ( <View style={{flex:1}}> <Animated.Image style={{ flex: 1, position: 'absolute', left: translateBackgroundImage1, }} resizeMode={Image.resizeMode.cover} source={this.backgroundImage} /> <Animated.Image style={{ flex: 1, position: 'absolute', left: translateBackgroundImage2, }} resizeMode={Image.resizeMode.cover} source={this.backgroundImage} />
要应用我用于setInterval()
的相同逻辑,我必须translateBackgroundImage1
从第一个循环中的x:0
开始,然后从x: ImageWidth
我不确定如何使用Animated
来实现这一点
我最终找到了解决方案。它不是很干净,但可以工作。
我基本上从同一图像加载了两个Animated.image
。然后我有一个translateValue1
,它控制第一个图像的左侧位置。然后基于translateValue1
,我们有translateValue2
具有imagewidth
offset
。translateValue2
控制第二个图像的左侧位置。
当第一张图片即将退出屏幕时,它会转到屏幕的最右侧,同时第二张图片会移动到第一张图片的前面,所以我们需要将offset
更改为-imagewidth
.因此,两个动画函数中的每一个都有一个setState
方法。
在构造函数中,我有这些变量:
constructor(props) {
super(props);
this.backgroundImage = require('../assets/images/graidenttPastel.jpg');
this.backgroundImageWidth = resolveAssetSource(this.backgroundImage).width;
this.translateXValue1 = new Animated.Value(-1);
this.translateXValue2 = new Animated.Value(0);
this.animationLength = 20000;
this.state = {
translateXValue2Offset: this.backgroundImageWidth,
stopAnimation: false,
}
然后我有两个函数,每个函数控制循环的一半:
translateXFirstHalfLoop() {
this.translateXValue1.setValue(-1);
this.setState({translateXValue2Offset: this.backgroundImageWidth});
this.firstHalfLoop = Animated.timing(
this.translateXValue1,
{
toValue: -this.backgroundImageWidth,
duration: this.animationLength/2,
easing: Easing.linear
}
).start(() => {
if(this.state.stopAnimation === false) {
this.translateXSecondHalfLoop()
}
})
}
translateXSecondHalfLoop() {
this.translateXValue1.setValue(this.backgroundImageWidth);
this.setState({translateXValue2Offset: -this.backgroundImageWidth});
this.secondHalfLoop = Animated.timing(
this.translateXValue1,
{
toValue: 0,
duration: this.animationLength/2,
easing: Easing.linear
}
).start(() => {
if(this.state.stopAnimation === false) {
this.translateXFirstHalfLoop()
}
})
}
最后在render()
方法中,我有两个Animated.Image
如下所示:
render() {
this.translateXValue2 = Animated.add(this.translateXValue1, this.state.translateXValue2Offset);
return (
<SafeAreaView
style={[{backgroundColor: THEME_COLOR, flex: 1}]}
forceInset={{ bottom: 'never' }}>
<Animated.Image
style={{
position: 'absolute',
left: this.translateXValue1,
}}
resizestate={Image.resizeMode.cover}
source={this.backgroundImage}
/>
<Animated.Image
style={{
position: 'absolute',
left: this.translateXValue2,
}}
resizestate={Image.resizeMode.cover}
source={this.backgroundImage}
/>
<View style={{flex:1}}>
{this._renderScreenContent()}
</View>
</SafeAreaView>
);
}
由于每个半循环函数都调用另一个半循环函数,因此我们需要在此组件卸载之前停止它们,因此我们在下面有这个额外的步骤:
//clean up animation first
this.setState({stopAnimation: true}, () => {
this.props.navigation.goBack()
})
如果您想为ImageBackground
制作动画,请尝试
var AnimatedImage = Animated.createAnimatedComponent(ImageBackground)