[英]Having a rendering issue with React-Native Animation
我在制作動畫時遇到了麻煩。我試圖用兩種不同的視圖翻轉卡片。 當用戶在兩張不同的卡片之間滾動時,我也試圖創建滾動效果。 當代碼以下面的方式組合時,它會創建一個我無法壓縮的錯誤。 我添加了一個圖像來直觀地表示我的問題。
我感謝任何幫助。
:
我的生命周期方法:
componentWillMount() {
this.animatedValue = new Animated.Value(0);
this.value = 0;
this.animatedValue.addListener(({ value }) => {
this.value = value;
this.setState({ value });
});
this.frontInterpolate = this.animatedValue.interpolate({
inputRange: [0, 180],
outputRange: ['0deg', '180deg']
});
this.backInterpolate = this.animatedValue.interpolate({
inputRange: [0, 180],
outputRange: ['180deg', '360deg']
});
}
}
此動畫用於生成翻轉動畫:
flipCard() {
if (this.value >= 90) {
this.setState({
isWaiting: true
});
Animated.spring(this.animatedValue, {
toValue: 0,
friction: 8,
tension: 10
}).start(() => {
this.setState({
isWaiting: false
});
});
} else {
this.setState({
isWaiting: true
});
Animated.spring(this.animatedValue, {
toValue: 180,
friction: 8,
tension: 10
}).start(() => {
this.setState({ isWaiting: false });
});
}
}
這是通過flipCard功能翻轉的View。 如果您在其中一個視圖中看到,則有一個名為transitionAnimation的函數。 這用於產生滾動效果。
<View style={styles.scrollPage}>
<View>
<Animated.View
style={[
frontAnimatedStyle,
styles.screen,
this.transitionAnimation(index)
]}
>
<Text style={styles.text}>{question.question}</Text>
</Animated.View>
<Animated.View
style={[
styles.screen,
backAnimatedStyle,
styles.back,
this.transitionAnimation(index)
]}
>
<Text style={styles.text}>{question.answer}</Text>
</Animated.View>
transitionAnimation:
transitionAnimation = index => {
if (!this.state.isWaiting) {
return {
transform: [
{ perspective: 800 },
{
scale: xOffset.interpolate({
inputRange: [
(index - 1) * SCREEN_WIDTH,
index * SCREEN_WIDTH,
(index + 1) * SCREEN_WIDTH
],
outputRange: [0.25, 1, 0.25]
})
},
{
rotateX: xOffset.interpolate({
inputRange: [
(index - 1) * SCREEN_WIDTH,
index * SCREEN_WIDTH,
(index + 1) * SCREEN_WIDTH
],
outputRange: ['45deg', '0deg', '45deg']
})
},
{
rotateY: xOffset.interpolate({
inputRange: [
(index - 1) * SCREEN_WIDTH,
index * SCREEN_WIDTH,
(index + 1) * SCREEN_WIDTH
],
outputRange: ['-45deg', '0deg', '45deg']
})
}
]
};
}
};
我的渲染功能:
render() {
const { flashcards } = this.state;
return (
<View style={styles.container}>
<View
style={{
alignItems: 'flex-end',
marginTop: 10
}}
>
<Progress.Circle
size={70}
showsText
progress={this.state.timer}
formatText={text => {
return (this.state.timer * 100).toFixed(0);
}}
/>
</View>
<Animated.ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: xOffset } } }],
{ useNativeDriver: true }
)}
horizontal
pagingEnabled
style={styles.scrollView}
>
{this.state.flashcards && this.renderCard()}
</Animated.ScrollView>
</View>
);
}
}
我還創建了一個小吃店,您可以在那里查看問題。 https://snack.expo.io/@louis345/flaschards
你有很多問題:
主要問題是因為您沒有正確存儲每張卡的狀態(如果它是否被翻轉)。 例如,您可以將flippedCards
Array或Set添加到您的狀態,並在每次翻轉卡片時更新它,以便在動畫結束時調用setState
后正確呈現,以及正確呈現未翻轉的其他卡片。
您可以一次渲染和動畫(翻轉和轉換)所有卡片,但是您應該只渲染三張卡片(當前和鄰居),並且您應該只翻轉當前卡片。
性能問題:您在每個渲染上創建過渡樣式和其他函數,這使得渲染非常慢。
其他應該重構的代碼。
我解決了1和3個問題,並重構了一下。 2取決於你:
import React, { Component } from 'react';
import { Animated, Dimensions, StyleSheet, Text, View, TouchableOpacity, TouchableWithoutFeedback } from 'react-native';
import { EvilIcons, MaterialIcons } from '@expo/vector-icons';
const SCREEN_WIDTH = Dimensions.get('window').width;
export default class App extends Component {
constructor(props) {
super(props);
const flashcards = ['konichiwa','hi','genki desu','how are you'];
this.state = {
flashcards,
flipped: flashcards.map(() => false),
flipping: false
};
this.flipValue = new Animated.Value(0);
this.frontAnimatedStyle = {
transform: [{
rotateY: this.flipValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '180deg']
})
}]
};
this.backAnimatedStyle = {
transform: [{
rotateY: this.flipValue.interpolate({
inputRange: [0, 1],
outputRange: ['180deg', '360deg']
})
}]
};
let xOffset = new Animated.Value(0);
this.onScroll = Animated.event(
[{ nativeEvent: { contentOffset: { x: xOffset } } }],
{ useNativeDriver: false }
);
this.transitionAnimations = this.state.flashcards.map((card, index) => ({
transform: [
{ perspective: 800 },
{
scale: xOffset.interpolate({
inputRange: [
(index - 1) * SCREEN_WIDTH,
index * SCREEN_WIDTH,
(index + 1) * SCREEN_WIDTH
],
outputRange: [0.25, 1, 0.25]
})
},
{
rotateX: xOffset.interpolate({
inputRange: [
(index - 1) * SCREEN_WIDTH,
index * SCREEN_WIDTH,
(index + 1) * SCREEN_WIDTH
],
outputRange: ['45deg', '0deg', '45deg']
})
},
{
rotateY: xOffset.interpolate({
inputRange: [
(index - 1) * SCREEN_WIDTH,
index * SCREEN_WIDTH,
(index + 1) * SCREEN_WIDTH
],
outputRange: ['-45deg', '0deg', '45deg']
})
}
]
}));
}
render() {
return (
<View style={styles.container}>
<Animated.ScrollView
scrollEnabled={!this.state.flipping}
scrollEventThrottle={16}
onScroll={this.onScroll}
horizontal
pagingEnabled
style={styles.scrollView}>
{this.state.flashcards.map(this.renderCard)}
</Animated.ScrollView>
</View>
);
}
renderCard = (question, index) => {
const isFlipped = this.state.flipped[index];
return (
<TouchableWithoutFeedback key={index} onPress={() => this.flipCard(index)}>
<View>
<View style={styles.scrollPage}>
<View>
{(this.state.flipping || !isFlipped) && <Animated.View
style={[
this.state.flipping ? this.frontAnimatedStyle : this.transitionAnimations[index],
styles.screen
]}
>
<Text style={styles.text}>{this.state.flashcards[index]}</Text>
</Animated.View>}
{(this.state.flipping || isFlipped) && <Animated.View
style={[
styles.screen,
this.state.flipping ? this.backAnimatedStyle : this.transitionAnimations[index],
this.state.flipping && styles.back
]}
>
<Text style={styles.text}>{this.state.flashcards[index+1]}</Text>
</Animated.View>}
</View>
</View>
<View style={styles.iconStyle}>
<TouchableOpacity>
<EvilIcons name="check" size={80} color={'#5CAF25'} />
</TouchableOpacity>
<TouchableOpacity>
<MaterialIcons name="cancel" size={70} color={'#b71621'} />
</TouchableOpacity>
</View>
</View>
</TouchableWithoutFeedback>
);
}
flipCard = index => {
if (this.state.flipping) return;
let isFlipped = this.state.flipped[index];
let flipped = [...this.state.flipped];
flipped[index] = !isFlipped;
this.setState({
flipping: true,
flipped
});
this.flipValue.setValue(isFlipped ? 1: 0);
Animated.spring(this.flipValue, {
toValue: isFlipped ? 0 : 1,
friction: 8,
tension: 10
}).start(() => {
this.setState({ flipping: false });
});
}
}
const styles = StyleSheet.create({
container: {
backgroundColor:'red',
flex: 1,
flexDirection: 'column',
justifyContent: 'space-between'
},
scrollView: {
flexDirection: 'row',
backgroundColor: 'black'
},
scrollPage: {
width: SCREEN_WIDTH,
padding: 20
},
screen: {
height: 400,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 25,
backgroundColor: 'white',
width: SCREEN_WIDTH - 20 * 2,
backfaceVisibility: 'hidden'
},
text: {
fontSize: 45,
fontWeight: 'bold'
},
iconStyle: {
flexDirection: 'row',
justifyContent: 'center'
},
back: {
position: 'absolute',
top: 0,
backfaceVisibility: 'hidden'
}
});
至少現在它工作正常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.