React Native transforms with pivot point

后端 未结 5 704
不思量自难忘°
不思量自难忘° 2021-01-02 03:02

I want to rotate a Text component with an angle of -90deg. The component should be rotated from the left corner instead of middle. I am using below

相关标签:
5条回答
  • 2021-01-02 03:10

    The follow code maybe helpful,the red view will transform 180 with the pivot point of (0.5,0), like iOS anchorPoint:

    /**
     * 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;
    
    0 讨论(0)
  • 2021-01-02 03:18
    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>
    
            );
    }
    

    NOTE: responsiveHeight, responsiveWidth are introduced in react-native-responsive-dimensions
    BackgroundTimer please check here react-native-background-timer
    Import some libraries

    0 讨论(0)
  • 2021-01-02 03:18

    I just made a withAnchorPoint function to make transform working with anchor point easier in react-native. https://github.com/sueLan/react-native-anchor-point.

    You can use it like this:

    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()]} />
    

    I also wrote an article for it.

    The following tricky codes are to set the anchor point or called pivot point of a view.

    1. translate the view by x, y, z on the x-axis, y-axis, z-axis
    2. apply rotation
    3. translate the view back by -x, -y, -z on the x-axis, y-axis, z-axis
              translateX: -w / 2
              rotateY
              translateX: w / 2
    

    This means setting the anchor point as (0, 0.5). We apply it in the transform style like this

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

    This means setting the anchor point as (1, 0.5)

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

    This means setting the anchor point as (0, 0)

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

    This means setting the anchor point as (1, 1)

    In iOS, it is called anchor point. About the anchorPoint

    layer.anchorPoint = CGPointMake(0, 0)
    
    

    In Android, it is called pivot point.

      viewToMove.setPivotX(0);
      viewToMove.setPivotY(0);
    
    0 讨论(0)
  • 2021-01-02 03:25

    I had pretty much the same problem. Here is how to do it

    Even though rotating with a pivot point is not directly supported, you can achieve the same result, with a combination of rotate, transformX and transformY - it's not to hard:

    1. Lets say we allready have the coordinates of the pivot point. In your case you could hook on the onLayout Event, that gives you x,y,width and height

    2. You take the center of the object to rotate. Again, onLayout is your Friend.

    3. Now take the x and y difference of both points, and use this handy formula, with angle beeing the angle you want to rotate:

      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")

    I leave it as an exercise to the reader to derive above formula :) Really it's simple trigonometry

    0 讨论(0)
  • 2021-01-02 03:26

    This issue on GitHub has a solution.

    If you're able to use an SVG, in your render method, you can do something like this:

    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>
    

    The this.state.offset is a hack for android which behaves differently. The onlayout to set that value looks like this.

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

    Note: using 25 as my x and y would rotate about the center.

    The user who posted the solution included this fully-functional example

    0 讨论(0)
提交回复
热议问题