我正在尝试使用一组图像在React Native中创建无限视差背景动画。我已经成功创建了动画。但是,动画播放的时间越长,它们看起来越不同步。
总体而言,我编写了按以下顺序创建三个动画的代码:
我将动画序列3-5循环放置,以便它们无限重复。
我也有同样的问题,而没有使用Expo。我还考虑过使视图位置不是绝对的,因此视图将被迫相互接触。但是,使用这种方法,当我要切换组件顺序时,我将不得不重新渲染。
我创建了this Expo项目来演示正在发生的事情。
这是我当前的代码:
App.js
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { Constants } from 'expo';
// You can import from local files
import ScrollingBackground from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<ScrollingBackground style={styles.scrollingBackground} images={[require('./assets/chess.png'),require('./assets/chess.png'),require('./assets/chess.png')]}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
},
scrollingBackground: {
width: '100%',
height: '100%',
backgroundColor: 'blue',
},
});
AssetExample.js
import React, { Component } from "react";
import {
StyleSheet,
View,
Animated,
Image,
Dimensions,
Easing
} from "react-native";
export default class ScrollingBackground extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
let imageComponents = [];
let lastImageYOffset = 0;
let counter = 0;
let deviceWidth = Dimensions.get("window").width;
this.props.images.forEach(image => {
const { width, height } = Image.resolveAssetSource(image);
let localElement = {};
let currentKey = "image" + counter.toString();
localElement.width = width;
localElement.height = (height * deviceWidth) / width;
localElement.initialOffset = lastImageYOffset;
localElement.topPositionAnimated = new Animated.Value(lastImageYOffset);
localElement.image = image;
localElement.currentKey = currentKey;
imageComponents.push(localElement);
lastImageYOffset = lastImageYOffset + localElement.height;
counter++;
});
lastImageYOffset = lastImageYOffset - imageComponents[imageComponents.length-1].height
this.setState({
imageComponents: imageComponents,
lastImageYOffset: lastImageYOffset
});
}
componentDidMount() {
let animations = [];
let arrayLength = this.state.imageComponents.length;
for (let i = 0; i < arrayLength; i++) {
// let height = -1 * this.state.imageComponents[i].height
// this.state.imageComponents[i].topPositionAnimated.addListener(({value}) => value == height ? console.log(this.state) : "");
animations.push(
Animated.sequence([
Animated.timing(this.state.imageComponents[i].topPositionAnimated, {
toValue: 0,
duration:
10 *
(this.state.imageComponents[i].initialOffset),
delay: 0,
easing: Easing.linear,
useNativeDriver: true
}),
Animated.timing(this.state.imageComponents[i].topPositionAnimated, {
toValue: -1 * this.state.imageComponents[i].height,
duration:
10 *
(this.state.imageComponents[i].height),
delay: 0,
easing: Easing.linear,
useNativeDriver: true
}),
Animated.loop(
Animated.sequence([
Animated.timing(this.state.imageComponents[i].topPositionAnimated, {
toValue: this.state.lastImageYOffset,
duration: 0,
delay: 0,
useNativeDriver: true
}),
Animated.timing(this.state.imageComponents[i].topPositionAnimated, {
toValue: 0,
duration:
10 *
(this.state.lastImageYOffset),
delay: 0,
easing: Easing.linear,
useNativeDriver: true
}),
Animated.timing(this.state.imageComponents[i].topPositionAnimated, {
toValue: -1 * this.state.imageComponents[i].height,
duration:
10 *
(this.state.imageComponents[i].height),
delay: 0,
easing: Easing.linear,
useNativeDriver: true
}),
])
)
])
);
}
Animated.parallel(animations).start();
}
render() {
let elements = [];
for (imageComponent of this.state.imageComponents) {
elements.push(
<Animated.Image
key={imageComponent.currentKey}
source={imageComponent.image}
style={{
position: "absolute",
width: "100%",
height: imageComponent.height,
transform: [
{
translateY: imageComponent.topPositionAnimated
}
],
backgroundColor: "white"
}}
/>
);
}
return (
<View
style={[
styles.container,
{ backgroundColor: this.props.style.backgroundColor }
]}
>
{elements}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
width: "100%",
height: "100%"
}
});
答案 0 :(得分:0)
由于对多个视图进行动画处理存在延迟问题,因此对包含所有单个图像视图的容器视图进行动画处理被认为是更好的选择。我最终为此创建了一个反应本机库:https://www.npmjs.com/package/react-native-scrolling-images