如何动态改变状态的React Native?

我正在构建一个自定义视图,该视图将根据设备方向旋转其内容。这个应用程式的方向锁定为纵向,我只想旋转一个视图。它获取当前设备方向,更新状态,然后使用更新后的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;
i530151196 回答:如何动态改变状态的React Native?

我遇到了同样的问题,并通过使用来自react-native-reanimated的Animated.View解决了它。 (来自标准react-native包的Animation.View也可能有效,但我没有检查过)。我不需要使用Animated值,我仍然只是使用状态中的实际值,并且它起作用了。

,

如果您直接从 React Native 使用 Animated.Value + Animated.View,您会没事的。 遇到了同样的问题并使用 Animated.Value 类字段解决了它(在您的情况下,我猜您会为此使用 useState,因为功能 + useEffect 来设置Animated.Valueprops.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 }} />
        );
    }
}

请注意,在我的示例中,我也有插值,因为我的输入以弧度为单位,我希望它以度为单位。

,

这是我完成的处理旋转的组件。当应用程序锁定为纵向时,它将根据设备方向旋转其子项。我确定这可以清理一些,但它对我的目的有效。

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,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;
,

这是一个错误,因为当 rotate 的值更新时,旋转应该会改变。一种解决方法是将视图的 key 属性也设置为旋转值。

例如:

return (
  <View
    key={rotate} // <~~~ fix!
    style={{transform: [{rotate}]}}
  >
    {props.children}
  </View>
)

我找到了这个解决方案 here

本文链接:https://www.f2er.com/3170131.html

大家都在问