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
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;
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
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.
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);
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:
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
You take the center of the object to rotate. Again, onLayout is your Friend.
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
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