React Native多动画组合报错:方块移动缩放翻转功能无法加载
Hey there! Let's fix the issues in your code step by step — right now there are a few syntax and logic mistakes that are causing the app to crash.
1. Typo in Interpolation Variable References
You defined frontInterpolate and backInterpolate as local variables in the render method, but you're trying to access them as this.frontInterpolate and this.backInterpolate — that's a direct cause of the crash. Just remove the this. prefix.
2. Incorrect onLayout Binding
Your onLayout is attached to the TouchableWithoutFeedback instead of the actual box view, so this._width and this._height will never get the correct dimensions of the colored square. Move the onLayout to the front Animated.View.
3. Uninitialized Dimensions & Layout Calculation
When the app first loads, this._width and this._height are undefined, which breaks the position calculation in startAnimation. Initialize them with the box's default size (150) first, and adjust the target position to account for the scaled size when moving to the center.
4. Missing backfaceVisibility for Flip Effect
Without setting backfaceVisibility: 'hidden', both the front and back of the box will be visible during the flip, which ruins the 3D effect. Add this style to both the front and back boxes.
5. Rotation Animation Best Practice
Using an Animated.Value from 0 to 1 (instead of 0 to 180) is more standard for animations, as it makes interpolation smoother and plays nicer with the native driver. We'll adjust the rotate animation to use this pattern.
Here's the fully fixed code:
import React, { Component } from 'react'; import { StyleSheet, View, Text, Animated, Dimensions, TouchableWithoutFeedback } from 'react-native'; export default class App extends Component { state = { animation: new Animated.ValueXY(), scaleAnimation: new Animated.Value(1), rotateAnimation: new Animated.Value(0) }; // Initialize box dimensions with default size _width = 150; _height = 150; startAnimation = () => { const { width, height } = Dimensions.get("window"); // Calculate target position accounting for scaled size (2x) const targetX = (width / 2) - (this._width * 2 / 2); const targetY = (height / 2) - (this._height * 2 / 2); Animated.parallel([ Animated.timing(this.state.animation.y, { toValue: targetY, duration: 500, useNativeDriver: true }), Animated.timing(this.state.animation.x, { toValue: targetX, duration: 500, useNativeDriver: true }), Animated.timing(this.state.scaleAnimation, { toValue: 2, duration: 500, useNativeDriver: true }) ]).start(() => { // Trigger flip animation after move/scale completes Animated.timing(this.state.rotateAnimation, { toValue: 1, duration: 500, useNativeDriver: true }).start(); }) } saveDimensions = (e) => { this._width = e.nativeEvent.layout.width; this._height = e.nativeEvent.layout.height; } render() { const animatedStyles = { transform: [ { translateX: this.state.animation.x }, { translateY: this.state.animation.y }, { scale: this.state.scaleAnimation } ] } // Use 0-1 range for interpolation, map to degrees const frontInterpolate = this.state.rotateAnimation.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '180deg'] }) const backInterpolate = this.state.rotateAnimation.interpolate({ inputRange: [0, 1], outputRange: ['180deg', '360deg'] }) const frontAnimatedStyle = { transform: [ { rotateY: frontInterpolate } ] } const backAnimatedStyle = { transform: [ { rotateY: backInterpolate } ] } return ( <View style={styles.container}> <TouchableWithoutFeedback onPress={this.startAnimation}> <View> <Animated.View style={[styles.box, animatedStyles, frontAnimatedStyle]} onLayout={this.saveDimensions} // Bind onLayout to the actual box > <Text>Front</Text> </Animated.View> <Animated.View style={[styles.box, styles.boxBack, backAnimatedStyle]}> <Text>Back</Text> </Animated.View> </View> </TouchableWithoutFeedback> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, }, box: { width: 150, height: 150, backgroundColor: 'tomato', position: 'absolute', top: 0, left: 0, alignItems: 'center', justifyContent: 'center', backfaceVisibility: 'hidden', // Hide back face when flipped }, boxBack: { backgroundColor: 'green', backfaceVisibility: 'hidden', // Hide front face when flipped }, });
With these fixes, your app will work as expected:
- The colored square starts at the top-left corner.
- When tapped, it animates to the center of the screen while scaling to twice its size.
- After that, it flips smoothly to show the green back side with the "Back" text.
内容的提问来源于stack exchange,提问作者W. Robarts

