我正在构建一个自定义视图,该视图将根据设备方向旋转其内容。这个应用程式的方向锁定为纵向,我只想旋转一个视图。它获取当前设备方向,更新状态,然后使用更新后的style={{transform: [{rotate: 'xxxdeg'}]}}
渲染新组件。
我正在使用react-native-orientation-locker
来检测方向变化。
视图渲染在第一个渲染上正确旋转。例如,如果在旋转设备时加载屏幕,它将使视图旋转。但是在更改设备或模拟器的方向时,视图不会旋转。它保持锁定在初始化时的rotate
值。
似乎对transform
rotate
值的更新不会改变旋转。我已验证在渲染过程中是否存在新的rotate
值。我已验证方向更改正确更新了状态。但是,当方向改变时,视图永远不会在UI中旋转。就像React Native在渲染期间没有对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;
答案 0 :(得分:1)
我遇到了同样的问题,并通过使用来自react-native-reanimated的Animated.View解决了它。 (来自标准react-native包的Animation.View也可能有效,但我没有检查过)。我不需要使用Animated值,我仍然只是使用状态中的实际值,并且它起作用了。
答案 1 :(得分:0)
如果您直接从 React Native 使用 Animated.Value
+ Animated.View
,您会没事的。
遇到了同样的问题并使用 Animated.Value
类字段解决了它(在您的情况下,我猜您会为此使用 useState
,因为功能 + useEffect
来设置Animated.Value
在 props.rotation
中发生变化),然后将其作为 Animated.View
transform = [{ rotate: animatedRotationValue }]
这是它的类组件形式的片段:
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 }} />
);
}
}
请注意,在我的示例中,我也有插值,因为我的输入以弧度为单位,我希望它以度为单位。
答案 2 :(得分:0)
这是我完成的处理旋转的组件。当应用程序锁定为纵向时,它将根据设备方向旋转其子项。我确定这可以清理一些,但它对我的目的有效。
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;
答案 3 :(得分:0)
这是一个错误,因为当 rotate
的值更新时,旋转应该会改变。一种解决方法是将视图的 key
属性也设置为旋转值。
例如:
return (
<View
key={rotate} // <~~~ fix!
style={{transform: [{rotate}]}}
>
{props.children}
</View>
)
我找到了这个解决方案 here。