React Native Animated 在第一次点击时不起作用
React Native Animated don't work on first click
我正在使用 React Native 创建一个扑克牌 table,我希望在点击椅子动画时发生(椅子围绕 table 排列)。
但是动画在第一次点击时不起作用,而在我点击第二次时动画起作用。
请查看下图
你可以看到 table 周围有 8 把椅子 我想要的是每当我点击任何 table 时,旋转应该以这样的方式进行 table 我点击应该替换掉绿色的table(下)
问题是在第一次点击时,useEffect 中的代码有效,但仍然没有出现动画。
这是代码
import {
Animated,
} from 'react-native';
function HomeScreen() {
const [shiftBy, setSiftBy] = React.useState(0);
const [p1InitialPosition] = React.useState(new Animated.ValueXY({ x: 180, y: 30 }));
const [p2InitialPosition] = React.useState(new Animated.ValueXY({ x: 325, y: 125 }));
const [p3InitialPosition] = React.useState(new Animated.ValueXY({ x: 338, y: 230 }));
const [p4InitialPosition] = React.useState(new Animated.ValueXY({ x: 335, y: 370 }));
const [p5InitialPosition] = React.useState(new Animated.ValueXY({ x: 180, y: 470 }));
const [p6InitialPosition] = React.useState(new Animated.ValueXY({ x: 30, y: 370 }));
const [p7InitialPosition] = React.useState(new Animated.ValueXY({ x: 30, y: 230 }));
const [p8InitialPosition] = React.useState(new Animated.ValueXY({ x: 40, y: 125 }));
const chairs = React.useMemo(() => {
return [
p1InitialPosition,
p2InitialPosition,
p3InitialPosition,
p4InitialPosition,
p5InitialPosition,
p6InitialPosition,
p7InitialPosition,
p8InitialPosition,
];
}, [
p1InitialPosition,
p2InitialPosition,
p3InitialPosition,
p4InitialPosition,
p5InitialPosition,
p6InitialPosition,
p7InitialPosition,
p8InitialPosition,
]);
// updated/animated positions
React.useEffect(() => {
const np = [];
for (let i = 0; i < chairs.length; i++) {
console.log(chairs[i], chairs[(i + shiftBy) % 8]);
np.push(
Animated.timing(chairs[i], {
toValue: chairs[(i + shiftBy) % 8],
duration: 800,
useNativeDriver: true,
}),
);
}
Animated.parallel(np).start();
console.log('');
}, [shiftBy]);
return (
<SafeAreaView style={styles.container}>
<Image
onLayout={event => {
const layout = event.nativeEvent.layout;
console.log('height:', layout.height);
console.log('width:', layout.width);
console.log('x:', layout.x);
console.log('y:', layout.y);
}}
source={require('../../assets/image/table/table.png')}
style={{
height: '100%',
width: '100%',
}}
/>
{/* p1 */}
<Animated.View
style={{
position: 'absolute',
transform: [{ translateX: p1InitialPosition.x }, { translateY: p1InitialPosition.y }],
}}>
<TouchableOpacity
// disabled={selectedChair}
onPress={() => setSiftBy(4)}>
<Icon name="chair" size={30} color="blue" />
</TouchableOpacity>
</Animated.View>
{/* p2 */}
<Animated.View
style={{
position: 'absolute',
transform: [{ translateX: p2InitialPosition.x }, { translateY: p2InitialPosition.y }],
}}>
<TouchableOpacity
// disabled={selectedChair}
onPress={() => setSiftBy(3)}>
<Icon name="chair" size={30} color="skyblue" />
</TouchableOpacity>
</Animated.View>
{/* p3 */}
{/* p4 */}
{/* p5 */}
{/* p6 */}
{/* p7 */}
{/* p8 */}
</SafeAreaView>
);
}
export default HomeScreen;
这是 link 完成屏幕代码- snack.expo.dev/sd7yF5CzZ
请帮忙。
解决方法是在你的代码中添加useLayoutEffect
:
React.useLayoutEffect(() => {
const np = [];
for (let i = 0; i < chairs.length; i++) {
console.log(chairs[i], chairs[(i + shiftBy) % 8]);
np.push(
Animated.timing(chairs[i], {
toValue: chairs[(i + shiftBy) % 8],
duration: 800,
useNativeDriver: true,
}),
);
}
Animated.parallel(np).start();
console.log('');
}, [shiftBy]);
说明
由于 useEffect
回调在渲染提交阶段之后调用,因此在渲染周期之后调用,并且 LayoutAnimation.configureNext
意味着“准备”下一个渲染,调用它已经太晚了useEffect
.
里面
所以解决方案是使用 useLayoutEffect
和 useEffect
来确保动画在第一次渲染时 运行
我正在使用 React Native 创建一个扑克牌 table,我希望在点击椅子动画时发生(椅子围绕 table 排列)。
但是动画在第一次点击时不起作用,而在我点击第二次时动画起作用。
请查看下图
你可以看到 table 周围有 8 把椅子 我想要的是每当我点击任何 table 时,旋转应该以这样的方式进行 table 我点击应该替换掉绿色的table(下)
问题是在第一次点击时,useEffect 中的代码有效,但仍然没有出现动画。
这是代码
import {
Animated,
} from 'react-native';
function HomeScreen() {
const [shiftBy, setSiftBy] = React.useState(0);
const [p1InitialPosition] = React.useState(new Animated.ValueXY({ x: 180, y: 30 }));
const [p2InitialPosition] = React.useState(new Animated.ValueXY({ x: 325, y: 125 }));
const [p3InitialPosition] = React.useState(new Animated.ValueXY({ x: 338, y: 230 }));
const [p4InitialPosition] = React.useState(new Animated.ValueXY({ x: 335, y: 370 }));
const [p5InitialPosition] = React.useState(new Animated.ValueXY({ x: 180, y: 470 }));
const [p6InitialPosition] = React.useState(new Animated.ValueXY({ x: 30, y: 370 }));
const [p7InitialPosition] = React.useState(new Animated.ValueXY({ x: 30, y: 230 }));
const [p8InitialPosition] = React.useState(new Animated.ValueXY({ x: 40, y: 125 }));
const chairs = React.useMemo(() => {
return [
p1InitialPosition,
p2InitialPosition,
p3InitialPosition,
p4InitialPosition,
p5InitialPosition,
p6InitialPosition,
p7InitialPosition,
p8InitialPosition,
];
}, [
p1InitialPosition,
p2InitialPosition,
p3InitialPosition,
p4InitialPosition,
p5InitialPosition,
p6InitialPosition,
p7InitialPosition,
p8InitialPosition,
]);
// updated/animated positions
React.useEffect(() => {
const np = [];
for (let i = 0; i < chairs.length; i++) {
console.log(chairs[i], chairs[(i + shiftBy) % 8]);
np.push(
Animated.timing(chairs[i], {
toValue: chairs[(i + shiftBy) % 8],
duration: 800,
useNativeDriver: true,
}),
);
}
Animated.parallel(np).start();
console.log('');
}, [shiftBy]);
return (
<SafeAreaView style={styles.container}>
<Image
onLayout={event => {
const layout = event.nativeEvent.layout;
console.log('height:', layout.height);
console.log('width:', layout.width);
console.log('x:', layout.x);
console.log('y:', layout.y);
}}
source={require('../../assets/image/table/table.png')}
style={{
height: '100%',
width: '100%',
}}
/>
{/* p1 */}
<Animated.View
style={{
position: 'absolute',
transform: [{ translateX: p1InitialPosition.x }, { translateY: p1InitialPosition.y }],
}}>
<TouchableOpacity
// disabled={selectedChair}
onPress={() => setSiftBy(4)}>
<Icon name="chair" size={30} color="blue" />
</TouchableOpacity>
</Animated.View>
{/* p2 */}
<Animated.View
style={{
position: 'absolute',
transform: [{ translateX: p2InitialPosition.x }, { translateY: p2InitialPosition.y }],
}}>
<TouchableOpacity
// disabled={selectedChair}
onPress={() => setSiftBy(3)}>
<Icon name="chair" size={30} color="skyblue" />
</TouchableOpacity>
</Animated.View>
{/* p3 */}
{/* p4 */}
{/* p5 */}
{/* p6 */}
{/* p7 */}
{/* p8 */}
</SafeAreaView>
);
}
export default HomeScreen;
这是 link 完成屏幕代码- snack.expo.dev/sd7yF5CzZ
请帮忙。
解决方法是在你的代码中添加useLayoutEffect
:
React.useLayoutEffect(() => {
const np = [];
for (let i = 0; i < chairs.length; i++) {
console.log(chairs[i], chairs[(i + shiftBy) % 8]);
np.push(
Animated.timing(chairs[i], {
toValue: chairs[(i + shiftBy) % 8],
duration: 800,
useNativeDriver: true,
}),
);
}
Animated.parallel(np).start();
console.log('');
}, [shiftBy]);
说明
由于 useEffect
回调在渲染提交阶段之后调用,因此在渲染周期之后调用,并且 LayoutAnimation.configureNext
意味着“准备”下一个渲染,调用它已经太晚了useEffect
.
所以解决方案是使用 useLayoutEffect
和 useEffect
来确保动画在第一次渲染时 运行