我正在构建一个自定义视图,它将根据设备方向旋转其内容。这个应用程序的方向锁定为肖像,我只想旋转一个单一的视图。它获取当前设备方向,更新状态,然后使用更新的style={{transform: [{rotate: 'xxxdeg'}]}}呈现新组件。
我使用react-native-orientation-locker来检测方向的变化。
视图在第一次呈现时正确地呈现旋转。例如,如果屏幕在设备旋转时加载,它将呈现视图旋转。但是,当改变设备或模拟器的方向时,视图不会旋转。它保持锁定在它被初始化的rotate值。
似乎对transform rotate值的更新不会改变旋转。我已经验证了在呈现过程中是否存在新的rotate值。我已经验证了方向更改是否正确地更新了状态。但是,当方向发生变化时,视图在UI中永远不会旋转。就好像React本机在呈现过程中没有接收到对rotate值的更改。
我希望对rotate值的更新会相应地旋转View,但情况似乎并非如此。还有其他方法来完成这个任务吗?还是我在这段代码中有错误?
编辑:rotate是否需要成为一个Animated值?
import React, {useState, useEffect} from 'react';
import {View} from 'react-native';
import Orientation from 'react-native-orientation-locker';
const RotateView = props => {
const getRotation = newOrientation => {
switch (newOrientation) {
case 'LANDSCAPE-LEFT':
return '90deg';
case 'LANDSCAPE-RIGHT':
return '-90deg';
default:
return '0deg';
}
};
const [orientation, setOrientation] = useState(
// set orientation to the initial device orientation
Orientation.getInitialOrientation(),
);
const [rotate, setRotate] = useState(
// set rotation to the initial rotation value (xxdeg)
getRotation(Orientation.getInitialOrientation()),
);
useEffect(() => {
// Set up listeners for device orientation changes
Orientation.addDeviceOrientationListener(setOrientation);
return () => Orientation.removeDeviceOrientationListener(setOrientation);
}, []);
useEffect(() => {
// when orientation changes, update the rotation
setRotate(getRotation(orientation));
}, [orientation]);
// render the view with the current rotation value
return (
<View style={{transform: [{rotate}]}}>
{props.children}
</View>
);
};
export default RotateView;发布于 2021-03-05 15:37:56
这是我完成的处理旋转的组件。当应用程序被锁定为肖像时,它将根据设备的方向旋转它的子程序。我相信这件事可以清理一些,但对我来说是可行的。
import React, {useState, useEffect, useRef} from 'react';
import {Animated, Easing, View, StyleSheet} from 'react-native';
import {Orientation} from '../utility/constants';
import OrientationManager from '../utility/orientation';
const OrientedView = (props) => {
const getRotation = useRef((newOrientation) => {
switch (newOrientation) {
case Orientation.LANDSCAPE_LEFT:
return 90;
case Orientation.LANDSCAPE_RIGHT:
return -90;
default:
return 0;
}
});
const {duration = 100, style} = props;
const initialized = useRef(false);
const [orientation, setOrientation] = useState();
const [rotate, setRotate] = useState();
const [containerStyle, setContainerStyle] = useState(styles.containerStyle);
// Animation kept as a ref
const rotationAnim = useRef();
// listen for orientation changes and update state
useEffect(() => {
OrientationManager.getDeviceOrientation((initialOrientation) => {
const initialRotation = getRotation.current(initialOrientation);
// default the rotation based on initial orientation
setRotate(initialRotation);
rotationAnim.current = new Animated.Value(initialRotation);
setContainerStyle([
styles.containerStyle,
{
transform: [{rotate: `${initialRotation}deg`}],
},
]);
initialized.current = true;
// set orientation and trigger the first render
setOrientation(initialOrientation);
});
OrientationManager.addDeviceOrientationListener(setOrientation);
return () =>
OrientationManager.removeDeviceOrientationListener(setOrientation);
}, []);
useEffect(() => {
if (initialized.current === true) {
const rotation = getRotation.current(orientation);
setRotate(
rotationAnim.current.interpolate({
inputRange: [-90, 0, 90],
outputRange: ['-90deg', '0deg', '90deg'],
}),
);
Animated.timing(rotationAnim.current, {
toValue: rotation,
duration: duration,
easing: Easing.ease,
useNativeDriver: true,
}).start();
}
}, [duration, orientation]);
// FIXME: This is causing unnessary animation outside of the oriented view. Disabling removes the scale animation.
// useEffect(() => {
// applyLayoutAnimation.current();
// }, [orientation]);
useEffect(() => {
if (initialized.current === true) {
setContainerStyle([
styles.containerStyle,
{
transform: [{rotate}],
},
]);
}
}, [rotate]);
if (initialized.current === false) {
return <View style={[containerStyle, style]} />;
}
return (
<Animated.View style={[containerStyle, style]}>
{props.children}
</Animated.View>
);
};
const styles = StyleSheet.create({
containerStyle: {flex: 0, justifyContent: 'center', alignItems: 'center'},
});
export default OrientedView;发布于 2020-01-05 12:13:12
我也遇到了同样的问题,并通过使用react的Animated.View来解决这个问题。(来自标准react的Animated.View-本机包也可能工作,但我还没有检查)。我不需要使用动画值,我仍然使用来自状态的实际值,而且它起了作用。
发布于 2021-03-05 01:17:24
如果您直接使用Animated.Value + Animated.View,直接使用react本机,您就可以了。有同样的问题,并使用Animated.Value类字段解决了这个问题(在您的例子中,我想您会对此字段使用一个useState,因为functional +a useEffect用于在props.rotation中更改时设置Animated.Value的值),然后将其作为transform = [{ rotate: animatedRotationValue }]传递到Animated.View中。
下面是作为代码片段的类组件形式:
interface Props {
rotation: number;
}
class SomethingThatNeedsRotation extends React.PureComponent<Props> {
rotation = new Animated.Value(0);
rotationValue = this.rotation.interpolate({
inputRange: [0, 2 * Math.PI],
outputRange: ['0deg', '360deg'],
});
render() {
this.rotation.setValue(this.props.rotation);
const transform = [{ rotate: this.rotationValue }];
return (
<Animated.View style={{ transform }} />
);
}
}请注意,在我的例子中,我也有插值,因为我的输入是弧度,我希望它是度。
https://stackoverflow.com/questions/58684624
复制相似问题