首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何用状态动态地改变本机变换?

如何用状态动态地改变本机变换?
EN

Stack Overflow用户
提问于 2019-11-03 21:05:14
回答 4查看 2.5K关注 0票数 4

我正在构建一个自定义视图,它将根据设备方向旋转其内容。这个应用程序的方向锁定为肖像,我只想旋转一个单一的视图。它获取当前设备方向,更新状态,然后使用更新的style={{transform: [{rotate: 'xxxdeg'}]}}呈现新组件。

我使用react-native-orientation-locker来检测方向的变化。

视图在第一次呈现时正确地呈现旋转。例如,如果屏幕在设备旋转时加载,它将呈现视图旋转。但是,当改变设备或模拟器的方向时,视图不会旋转。它保持锁定在它被初始化的rotate值。

似乎对transform rotate值的更新不会改变旋转。我已经验证了在呈现过程中是否存在新的rotate值。我已经验证了方向更改是否正确地更新了状态。但是,当方向发生变化时,视图在UI中永远不会旋转。就好像React本机在呈现过程中没有接收到对rotate值的更改。

我希望对rotate值的更新会相应地旋转View,但情况似乎并非如此。还有其他方法来完成这个任务吗?还是我在这段代码中有错误?

编辑:rotate是否需要成为一个Animated值?

代码语言:javascript
复制
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;
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2021-03-05 15:37:56

这是我完成的处理旋转的组件。当应用程序被锁定为肖像时,它将根据设备的方向旋转它的子程序。我相信这件事可以清理一些,但对我来说是可行的。

代码语言:javascript
复制
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;
票数 0
EN

Stack Overflow用户

发布于 2020-01-05 12:13:12

我也遇到了同样的问题,并通过使用react的Animated.View来解决这个问题。(来自标准react的Animated.View-本机包也可能工作,但我还没有检查)。我不需要使用动画值,我仍然使用来自状态的实际值,而且它起了作用。

票数 2
EN

Stack Overflow用户

发布于 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中。

下面是作为代码片段的类组件形式:

代码语言:javascript
复制
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 }} />
        );
    }
}

请注意,在我的例子中,我也有插值,因为我的输入是弧度,我希望它是度。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58684624

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档