I am trying to pass style to children, my code is :
render() {
const RotateData = this.RotateValueHolder.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
});
Object.assign(this.props.children.props.style,{'transform': [{'rotate': RotateData}] });
return (
<View style={{flex:1}}>
{this.props.children}
</View>
);
}
I getting this error :
Invariant Violation: Transform with key of "rotate" must be a string:
{"rotate":"0deg"}
Rotate can be only used by the animated component, so you need to apply the style to Animated.View or any Animated element. so try to use it with animated component.
Related
I have a Pressable component and inside it I have an icon. I want to press it and rotate it 180 degrees, how can I do that?
So to do this you must take use of the Animated library from react-native.
In which you make animated values and make functions to update them. Here's a full sample of you want (https://snack.expo.dev/#heytony01/grumpy-pretzel) and below is the explantion.
First import the library and make an Animated value
import { Text, View, StyleSheet,Animated,TouchableWithoutFeedback } from 'react-native';
const spinValue = React.useState(new Animated.Value(0))[0]; // Makes animated value
Next define functions to change the value
// When button is pressed in, make spinValue go through and up to 1
const onPressIn = () => {
Animated.spring(spinValue, {
toValue: 1,
useNativeDriver: true,
}).start();
};
// When button is pressed out, make spinValue go through and down to 0
const onPressOut = () => {
Animated.spring(spinValue, {
toValue: 0,
useNativeDriver: true,
}).start();
};
The tricky part is that in order to rotate in react-native you need to pass "0deg" or "12deg" etc..
<View style={{
transform: [
{ rotate: "45deg" },
]
}}>
</View>
So what you do is you interpolate the animated value to "0deg" to "360deg"
// spinDeg will be between '0deg' and '360deg' based on what spinValue is
const spinDeg = spinValue.interpolate({
useNativeDriver: true,
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
Lastly you pass in the spinDeg into your button and your done
// The animated style for scaling the button within the Animated.View
const animatedScaleStyle = {
transform: [{rotate: spinDeg}]
};
return (
<View style={{flex:1,justifyContent:"center",alignItems:"center"}}>
<TouchableWithoutFeedback
onPress={()=>{}}
onPressIn={onPressIn}
onPressOut={onPressOut}
>
<View style={{justifyContent:"center",alignItems:"center",backgroundColor:"lightgray",padding:15,borderRadius:20}}>
<Text>PRESS ME</Text>
<Animated.View style={[styles.iconContainer, animatedScaleStyle]}>
<Ionicons name="md-checkmark-circle" size={32} color="green" />
</Animated.View>
</View>
</TouchableWithoutFeedback>
</View>
);
Below code is to render a Touchable button with Transform Animation.
const { scrollY, headerScrollDistance } = this.state;
const profileImageTranslateX = scrollY.interpolate({
inputRange: [0, headerScrollDistance],
outputRange: [0, -(ScreenWidth /2) + 32],
extrapolate: 'clamp',
});
const profileImageTranslateY = scrollY.interpolate({
inputRange: [0, headerScrollDistance],
outputRange: [0, -11],
extrapolate: 'clamp',
});
const profileImageScale = scrollY.interpolate({
inputRange: [0, headerScrollDistance / 2, headerScrollDistance],
outputRange: [1, 0.8, 0.6],
extrapolate: 'clamp',
});
return (
<Animated.View
style={[
Styles.animatedView.profileStyle,
{
transform: [
{ translateX: profileImageTranslateX },
{ translateY: profileImageTranslateY },
{ scale: profileImageScale }
]
}
]}
>
<TouchableOpacity activeOpacity={0.5} onPress={() => this.props.history.push('./profilePhotoChanger')}>
<ImageComp profileImageUrl={profileimageurl} imageStyle={Styles.homePageImageStyle} />
</TouchableOpacity>
</Animated.View>
);
As page scrolls, Animation applies to Touchable button. Button is working as expected when transform animation is not applied. But not working when animation is applied. If page comes back to it's normal state(i.e scrolling back) then button works as expected.
Is it normal behaviour in react-native that TouchableOpacity's onPress wont't work when animation applied? or is something wrong with my code?
You can try one of the following option if it works for you
1- import { TouchableOpacity } from 'react-native-gesture-handler';
2- Change height of Animated.View which contain TouchableOpacity (to
fit size of TouchableOpacity)
3- By moving <Animated.View> inside TouchableOpacity
Look like there is open discussion on Touchableopacity not working inside Animated.View
An re-animation (1.13) is used to toggle accordion in React Native app. When accordion is open or close, an arrow is up or down. interpolate is used to animate when arrow from up to down or vise verse.
import Animated, { useValue, interpolate, Easing, useCode, State, greaterThan, lessThan } from "react-native-reanimated";
const animatedController = useValue(0); //<<==animated value between [0, 1]
const arrowAngle = interpolate(animatedController, { //<<==interpolate causes error of node cannot be cast to number
inputRange: [0, 0.5, 1],
outputRange: ['0rad', `${0.5*Math.PI}rad`,`${Math.PI}rad`],
extrapolate: Extrapolate.CLAMP,
});
return (
<>
<TouchableWithoutFeedback onPress={() => setOpen(!open)}>
<View style={styles.titleContainer}>
<Text>{title}</Text>
<Animated.View style={{ transform: [{ rotateZ: arrowAngle }] }}> //<<==arrowAngle call here
<Icon name="chevron-down-outline" size={20} />
</Animated.View>
</View>
</TouchableWithoutFeedback>
</>
)
However the method above causes the error of node cannot be cast to number as below. This interpolate seems very simple. What's wrong here?
The output range shall be a number like this:
const arrowAngle = interpolate(animatedController, {
inputRange: [0, 0.5, 1],
outputRange: [0.01, 1/2*Math.PI,Math.PI], //<<==shall be digital
extrapolate: Extrapolate.CLAMP,
});
I am trying to animate a View to increase in height and overlap an image using the Animate tool from React-Native. The problem is that when I try this I keep getting an error
Tried to get frame out of range index NaN
I used this code for a previous project of mine and it worked fine, however I'm not sure what the issue is now. Here is my code:
export default class InformationScreen extends React.Component {
constructor(props){
super(props);
this.state={
scrollY: new Animated.Value(0),
}
}
render() {
const headerHeight = this.state.scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT],
});
return (
<View>
<Image style={{width:SCREEN_WIDTH, height:SCREEN_WIDTH}} resizeMode="cover" source={this.state.data.featured_image? {uri: this.state.data.featured_image} : require('../assets/noImage.jpg')}/>
<ScrollView style={{flex: 1, width:SCREEN_WIDTH, height: SCREEN_HEIGHT/0.99, alignSelf:'center', position: 'absolute'}} scrollEventThrottle={16} onScroll={Animated.event([{nativeEvent: {contentOffset: {y: this.state.scrollY}}}])}>
<Animated.View style={{height:headerHeight}}>
//information goes here
</Animated.View>
</ScrollView>
</View>
)}
}
Seems like I did everything in the documentation and referenced other examples.
Trying to animate a text component rotation:
this.state = {
rotateAnimation: new Animated.Value(0),
};
spin = () => {
this.state.rotateAnimation.setValue(0);
Animated.timing(this.state.rotateAnimation, {
toValue: 1,
duration: 3000,
easing: Easing.linear
}).start((animation) => {
if (animation.finished) {
this.spin();
}
});
};
render() {
return (
<Content>
<View>
<Text style={{
transform: [
{
rotate:
this.state.rotateAnimation.interpolate({
inputRange: [0, 1],
outputRange: ["0deg", "360deg"]
})
}
]
} ]}>{this.FAIcons.circleONotch}</Text>
</View>
</Content>
);
}
This works fine if I manually enter in any degree i.e rotate: "90deg"
However, when I use interpolate(), I get this error: Transform with key of "rotate" must be a string: {"rotate":"0deg"}
Seems like Interpolate is not returning a string. I tried to typecast it using "toString()" but then I get this error: Rotate transform must be expressed in degrees (deg) or radians (rad): {"rotate":"[object Object]"}
I followed this documentation: https://facebook.github.io/react-native/docs/animations.html
And referenced this example: https://gist.github.com/levynir/5962de39879a0b8eb1a2fd77ccedb2d8
What am I doing wrong here?
**** EDIT ****
Thanks to #Guilherme Cronemberger for pointing me in the right direction, you need to create the component like this.
render() {
const StyledAnimatedText = Animated.createAnimatedComponent(Text);
}
Then utilize it like this:
return (
<StyledAnimatedText
style={{
fontFamily: 'FontAwesome',
backgroundColor: 'transparent',
transform: [{
rotate: this.state.rotateAnimation.interpolate({
inputRange: [0, 1],
outputRange: ["0deg", "360deg"]
})
},
{ perspective: 1000 }]
}}>
{this.FAIcons.circleONotch}
</StyledAnimatedText>
)
Interpolate is a function which results are used only in declared "Animated" classes, so you'd add "Animated." to your Text class.
render() {
var rotateProp = this.state.rotateAnimation.interpolate({
inputRange: [0, 1],
outputRange: ["0deg", "360deg"]
})
console.log(rotateProp) //just to check if it's returning what you want
return (
<Content>
<View>
<Animated.Text style={{
transform: [
{
rotate: rotateProp
}
]
} ]}>{this.FAIcons.circleONotch}</Animated.Text>
</View>
</Content>
);
}
I had the same problem
Just use <Animated.Text> instead of <Text />
I had the same issue
I fixed it by using <Animated.SomeComponent> instead of <SomeComponent>
As an example if you want to animate View component :
import { Animated, View } from 'react-native';
<Animated.View>
<ChildComponents/>
</Animated.View>
Thanks.
I had the same problem and I fix it by doing this.Convert PI in degree = (PI = 180deg) & (2 * PI= 360geg),
The answer is :
{ rotate: progress.interpolate(
{
inputRange: [0.5, 1],
outputRange: ['180deg', '360deg'],
}
),
},