如何在 React Native 中使用 Animated 制作循环图像背景



我最初使用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()导致与在线库中的另一个组件发生冲突,所以我改用AnimatedAPI 并具有以下代码:

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具有imagewidthoffsettranslateValue2控制第二个图像的左侧位置。

当第一张图片即将退出屏幕时,它会转到屏幕的最右侧,同时第二张图片会移动到第一张图片的前面,所以我们需要将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)

相关内容

  • 没有找到相关文章

最新更新