【问题标题】:React Native transforms with pivot pointReact Native 转换与枢轴点
【发布时间】:2016-09-07 00:52:34
【问题描述】:

我想以-90deg 的角度旋转Text 组件。组件应该从左角而不是中间旋转。我正在使用以下代码:

render() {
     return (
            <View style = {{flex : 1}}>
                <View style={styles.sidebar}>
                    <Text style={styles.lblSideBar} numberOfLines = {1} >DUMMY TEXT</Text>
                </View>
            </View>);
}

const styles = StyleSheet.create({
  sidebar : {
    flex : 1,
    flexDirection : 'row',
    alignItems : 'flex-end',
    justifyContent : 'center',
    width : 30,
  },
  lblSideBar : {
      bottom : 20,
      transform : [{rotate : '-90deg'}],
  }
});

我想要 20px 的底部空间,但由于旋转是从中心发生的(默认情况下),旋转后文本会覆盖底部区域。请建议如何实现? 另外react-native需要pivotPoint或者anchorPoint或者transformOrigin的支持,这样才能轻松实现这个属性。

【问题讨论】:

  • 我想了想,有了以下想法。如果我们将文本放入视图中,然后旋转该视图会怎样。然后我们将 Text 定位在 View 的绝对左上角。这对我有用。我不确定如何制作一个工作示例 atm,但也许有人有时间可以发布答案

标签: transform react-native


【解决方案1】:

在做一个项目时,我在尝试围绕某个点旋转图像时遇到了一个问题,我无法在 react native 中执行此操作,因为您可以通过使用 css 来做到这一点,但在 react native 中您不能使用 css 所以我想出了一个办法。

  1. 将您的图像转换为 SVG,如果您使用矢量图像会更好。 (您可以通过使用许多在线工具来做到这一点,例如或使用 adobe illustrator,您可以在其中获取 SVG 代码)。

  2. 然后访问该网站,您将在该网站上将您的 SVG 代码转换为 JSX。我喜欢这个网站,因为通过使用这个网站,你可以将你的 for react native 转换为 react native。

  3. 然后你可以在你的代码中添加 JSX 并运行它,但在从这里安装 react-native-svg 之前。

  4. 然后根据您的选择将整个路径或SVG中的任何内容分组到您可以执行操作的位置。

//这里的rotate props 是按照角度的顺序来旋转的,x 和y 坐标是你要围绕它旋转图像的坐标。 ……

或类似的操作

……

您可以在此处查看实时示例。

https://snack.expo.io/@ajay19293/rotate-image-around-a-pivot-point-

【讨论】:

    【解决方案2】:

    我刚刚创建了一个withAnchorPoint 函数,以便在 react-native 中更轻松地使用锚点进行转换。 https://github.com/sueLan/react-native-anchor-point

    你可以这样使用它:

    import { withAnchorPoint } from 'react-native-anchor-point';
    
    getTransform = () => {
        let transform = {
            transform: [{ perspective: 400 }, { rotateX: rotateValue }],
        };
        return withAnchorPoint(transform, { x: 0.5, y: 0 }, { width: CARD_WIDTH, height: CARD_HEIGHT });
    };
    
    <Animated.View style={[styles.blockBlue, this.getTransform()]} />
    

    我还为此写了一篇文章。

    以下棘手的代码是设置锚点或称为视图的枢轴点。

    1. 在x轴、y轴、z轴上按x、y、z平移视图
    2. 应用轮换
    3. 在 x 轴、y 轴、z 轴上将视图平移 -x、-y、-z
              translateX: -w / 2
              rotateY
              translateX: w / 2
    

    这意味着将锚点设置为 (0, 0.5)。我们像这样在变换样式中应用它

       const transform = {
          transform: [
              {translateX: -w / 2}, 
              rotateY, 
              {translateX: w / 2}
          ]
        }
        return (   
            <Animated.View style={transform}></Animated.View>
        )
      }
    
    
              translateX: w / 2
              rotateY
              translateX: -w / 2
    

    这意味着将锚点设置为 (1, 0.5)

              translateX: -w / 2
              translateY: -h / 2
              rotateZ
              translateX: w / 2
              translateY: h / 2
    

    这意味着将锚点设置为 (0, 0)

              translateX: w / 2
              translateY: h / 2
              rotateZ
              translateX: -w / 2
              translateX: -h / 2
    

    这意味着将锚点设置为 (1, 1)

    在 iOS 中,它被称为锚点。 About the anchorPoint

    layer.anchorPoint = CGPointMake(0, 0)
    
    

    在 Android 中,它被称为枢轴点。

      viewToMove.setPivotX(0);
      viewToMove.setPivotY(0);
    

    【讨论】:

      【解决方案3】:

      This issue on GitHub 有解决办法。

      如果您能够使用 SVG,在您的渲染方法中,您可以执行以下操作:

      const pointX = 25;
      const pointY = 25;
      <Svg onLayout={this.onLayout} viewBox="0 0 50 50">
        {/* Rotate about point x y */}
        <G transform={`translate(${pointX}, ${pointY})`}>
          {/* Everything in AnimatedG gets rotated */}
          <AnimatedG style={{
            transform: [
              {
                translateX: -this.state.offset
              },
              {
                rotate: animation.interpolate({
                  inputRange: [0, 1],
                  outputRange: ['0deg', '360deg']
                })
              },
              {
                translateX: this.state.offset
              }
            ]
          }}>
            <G transform={`translate(-${pointX}, -${pointY})`}>
              <Path fill={this.props.color} d="M4.295 0A4.233 4.233 0 001.24 1.24l.75.75a3.175 3.175 0 012.243-.932 3.175 3.175 0 012.244.932l.75-.75A4.233 4.233 0 004.295 0z" />
            </G>
          </AnimatedG>
        </G>
      </Svg>
      

      this.state.offset 是针对 android 的 hack,其行为方式不同。设置该值的 onlayout 如下所示。

      onLayout = Platform.OS === 'android'
          ? e => { this.setState({ offset: e.nativeEvent.layout.width / 2 }) }
          : null;
      

      注意:使用 25 作为我的 x 和 y 将围绕中心旋转。

      发布解决方案的用户包括this fully-functional example

      【讨论】:

        【解决方案4】:
        constructor(props) {
             super(props)
             this.state = {
                  angle: 0
             }
        }
        
        componentDidMount() {
            this.progress()
        }
        
        progress(){
             intervalId = BackgroundTimer.setInterval(() => {      
                 this.setState({angle: this.state.angle +1})   
             }, (1000); // 1000 milliseconds
        }
        
        
        
        render () {
                const dx = responsiveHeight(9.5);
                const dy = responsiveHeight(9.5);
        
                const position= {
                    transform: [
                      {
                        translateX: Math.cos((360 - this.state.angle)  * Math.PI / 180) * dx - Math.sin((360 - this.state.angle) * Math.PI / 180) * dy
                      },
                      {
                        translateY:  Math.sin((360 - this.state.angle)  * Math.PI / 180) * dx + Math.cos((360 - this.state.angle) * Math.PI / 180) * dy
                      }
                    ]
                  };
        
                return(
                    <Animated.View style={position}>
                        <Text>Text move</Text>
                    </Animated.View>
        
                );
        }
        

        注意:responsiveHeight、responsiveWidth 是在 反应原生响应维度
        BackgroundTimer 请在此处查看 react-native-background-timer
        导入一些库

        【讨论】:

          【解决方案5】:

          下面的代码可能会有所帮助,红色视图会以 (0.5,0) 为轴心点转换 180,如 iOS 锚点:

          /**
           * Created by YQB on 16/9/14.
           */
          import React, {Component} from 'react';
          import {StyleSheet,View,Animated,Easing} from 'react-native';
          
          var dimensions =  require('Dimensions') ;
          var bgHeight = dimensions.get('window').height;
          var bgWidth = dimensions.get('window').width;
          var viewHeight = 100;
          
          class RotaTest extends Component {
              constructor(props) {
                  super(props);
                  this.state = {
                      transformView: new Animated.Value(0),
                  };
              }
              componentDidMount() {
                  Animated.timing(this.state.transformView,{toValue:1,duration:1000}).start();
              }
              render() {
                  return(
                      <View style={{flex:1}}>
                          <View style={layouts.lineLayout}/>
                          <Animated.View
                              style={[layouts.bgViewLayout,{transform:[
                                  {translateY: -viewHeight/2},
                                  {rotateX:this.state.transformView.interpolate({inputRange:[0,1], outputRange:['0deg','180deg']})},
                                  {translateY:viewHeight/2}
                              ]}]}/>
                      </View>
                  );
              }
          }
          const layouts = StyleSheet.create({
              bgViewLayout:{
                  width:bgWidth * 0.3,
                  height:viewHeight,
                  top: 100,
                  left:100,
                  backgroundColor:'red'
              },
              lineLayout:{
                  width:bgWidth,
                  height:0.5,
                  top:100,
                  backgroundColor:'black'
              }
          });
          export default RotaTest;
          

          【讨论】:

            【解决方案6】:

            我遇到了几乎同样的问题。 这是怎么做的

            即使不直接支持使用枢轴点进行旋转,您也可以通过组合旋转、transformX 和 transformY 来获得相同的结果 - 这并不难:

            1. 假设我们已经有了轴心点的坐标。 在您的情况下,您可以挂钩 onLayout 事件,它为您提供 x、y、宽度和高度

            2. 您以对象的中心为中心进行旋转。同样,onLayout 是你的朋友。

            3. 现在取两个点的 x 和 y 差,并使用这个方便的公式, 角度为您要旋转的角度:

              rad = angle * Math.PI / 180 transformX(Math.cos(angle) * dx - Math.sin(angle) * dy) transformY(Math.sin(angle) * dx + Math.cos(angle) * dy) rotate(angle+"deg")

            我把它作为一个练习留给读者推导出上面的公式:) 真的是简单的三角函数

            【讨论】:

            • 非常感谢!但对我来说,它只适用于设置 translateY >.
            • dxdy 是什么?
            • “我把它作为练习留给读者......”最后稍微挥手的部分答案并不酷。
            猜你喜欢
            • 1970-01-01
            • 2018-03-05
            • 2015-07-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多