Error while doing animations on react native - javascript

I'm having problem while trying to do animations on react native
it throws an error that says I can't assign the x value. Anybody knows what can it be?
undefined is not an object (evaluating '_this.state.animateXY.xinterpolate')
import {
View,
Text,
StyleSheet,
Animated,
Image,
Easing,
TouchableHighlight,
Dimensions,
} from 'react-native';
const {width, height} = Dimensions.get('window');
class AddPost extends Component {
constructor(){
super()
this.state ={
animate: new Animated.Value(30),
animateXY: new Animated.Value({x:0, y:0}),
// radius: new Animated.Value(0)
}
this.animateInterpolate = this.state.animateXY.x.interpolate({
inputRange: [0,150],
outputRange: [1,2]
})
}
componentWillMount(){
Animated.sequence([
Animated.timing(this.state.animateXY, {
toValue: {x: height / 2, y: 0},
duration:2000
}),
Animated.timing(this.state.animate, {
toValue: 60,
duration:2000
}),
/*Animated.timing(this.state.animate, {
toValue: 40,
duration:2000
}),*/
]).start()
}
render() {
return (
<TouchableHighlight onPress={onPress}>
<View style={styles.container}>
<Animated.View style={{
width: this.state.animate,
height: this.state.animate,
backgroundColor: 'blue',
position: 'absolute',
top: this.state.animateX.x,
left: this.state.animateY.y,
// transform:[{scale: this.animateInterpolate}],
borderRadius: this.state.radius
}}/>
</View>
</TouchableHighlight>
);
}
}

this.state.animateX is simply not declared.
You need to set animatedXY to 0 : animateX: new Animated.Value(0)
Then set your animation :
Animated.timing(this.state.animateX, {
toValue: height/2,
duration:2000
}),
Then you can set the value of your X :
top: this.state.animateX

Use Animated.ValueXY insted of Animated.Value
animateX : new Animated.ValueXY({x: 0, y: 0});

Related

Circling motion animation in React Native

I need to create an animation with an image that will circle around another image. I have already tried to use suggestions from a similar question like Animate a Circle around another circle , but unfortunately it didn't help. I tried looking into 3rd party modules that would offer the desirable functionality, but haven't found something that would fit my need.
I found a helpful article to understand the circular motion in JavaScript, however I have a hard time to replicate it in React Native animation. I believe I simply have a hard time understanding a proper usage of Animated API and transform style properties when it comes to animating circular movement.
<View style={animationContainer}>
<Image
source={require('./images/image.png')}
style={image}
/>
<Animated.Image
source={require('./images/icon.png')}
style={circlingIcon}
/>
</View>
I have posted a similar butter smooth solution for the question react native circle transform translate animation
Full code:
import React, {Component} from 'react';
import {View, Text, Animated, StyleSheet, Easing} from 'react-native';
export default class Circle extends Component {
constructor() {
super();
this.animated = new Animated.Value(0);
var inputRange = [0, 1];
var outputRange = ['0deg', '360deg'];
this.rotate = this.animated.interpolate({inputRange, outputRange});
outputRange = ['0deg', '-360deg'];
this.rotateOpposit = this.animated.interpolate({inputRange, outputRange});
}
componentDidMount() {
this.animate();
}
animate() {
Animated.loop(
Animated.timing(this.animated, {
toValue: 1,
duration: 4000,
useNativeDriver: true,
easing: Easing.linear,
}),
).start();
}
render() {
const transform = [{rotate: this.rotate}];
const transform1 = [{rotate: this.rotateOpposit}];
return (
<View style={styles.container}>
<Animated.View style={[styles.item, {transform}]}>
<Animated.View style={[styles.topItem, {transform: transform1}]}>
<Text style={styles.text}>Test</Text>
</Animated.View>
</Animated.View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
item: {
position: 'absolute',
width: 100,
height: 200, // this is the diameter of circle
},
topItem: {
width: '100%',
height: 20,
backgroundColor: 'red',
position: 'absolute',
alignItems: 'center',
justifyContent: 'center',
},
text: {
color: '#fff',
},
});
I hope it will help you..
I have taken a solution from a question react native circle transform translate animation and refactored it a little by separating interpolation of coordinates over Y and X in two different functions.
interface InterpolatedMotion {
translateX: Animated.Value;
translateY: Animated.Value;
}
interface AnimatedIcon extends InterpolatedMotion {
animated: Animated.Value;
}
interface State {
icon: AnimatedIcon;
}
const defaultAnimatedIcon = (animatedValue: number): AnimatedIcon => ({
animated: new Animated.Value(animatedValue),
translateX: new Animated.Value(0),
translateY: new Animated.Value(0),
});
export class Animation extends PureComponent<Props, State> {
state = {
icon: defaultAnimatedIcon(0),
}
constructor(props) {
super(props);
let { icon } = this.state;
icon.animated.setValue(0);
const snapshot = 50;
const radius = 200;
const inOutX = this.interpolateCircularMotionOverX(snapshot, radius);
icon.translateX = coins.animated.interpolate(inOutX);
const inOutY = this.interpolateCircularMotionOverY(snapshot, radius);
icon.translateY = coins.animated.interpolate(inOutY);
}
componentWillMount(): void {
this.startAnimation();
}
startAnimation = (): void => {
let { icon } = this.state;
icon.animated.setValue(0);
let animations = [
Animated.timing(
icon.animated,
{
toValue: 1,
duration: 8000,
easing: Easing.linear,
},
),
];
Animated.loop(
Animated.parallel(animations),
).start(() => {
icon.animated.setValue(0);
});
}
interpolateCircularMotionOverX = (snapshot: number, radius: number) => {
const inputRange = [];
const outputRange = [];
for (let i = 0; i <= snapshot * 2; ++i) {
const value = i / snapshot;
const move = Math.sin(value * Math.PI * 2) * radius;
inputRange.push(value);
outputRange.push(move);
}
return { inputRange, outputRange };
}
interpolateCircularMotionOverY = (snapshot: number, radius: number) => {
const inputRange = [];
const outputRange = [];
for (let i = 0; i <= snapshot * 2; ++i) {
const value = i / snapshot;
const move = -Math.cos(value * Math.PI * 2) * radius;
inputRange.push(value);
outputRange.push(move);
}
return { inputRange, outputRange };
}
render(): JSX.Element {
const { icon } = this.state;
const transformIcon = [
{ translateY: icon.translateY },
{ translateX: icon.translateX },
];
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ flex: 1 }}>
<Animated.Image
source={require('./images/coins.png')}
style={[Styles.forms.circlingIcon, { transform: transformCoins }]}
/>
</View>
</View>
);
}
This has helped me by providing a flexible and reusable solution for any future instances of circular animation.

sound is not played using react-native-sound

Im new to react-native and Im building an app to play sounds on button press and I couldnt achieve this, is it because of errors in my code ? Also pls suggest the solution for playing the sounds and suggest the corrections
Here's my code:
import React, { Component } from 'react';
import { StatusBar, Dimensions, Image, TouchableWithoutFeedback, Animated } from 'react-native';
import { Actions } from 'react-native-router-flux';
import Sound from 'react-native-sound';
const a = require('./Images/landing-bnt1-on.png');
const b = require('./Images/landing-bnt1.png');
const c = require('./Images/landing-bnt2-on.png');
const d = require('./Images/landing-bnt2.png');
const btnSound = new Sound('./Sounds/btn_sound.mp3');
const w = Dimensions.get('window').width;
const h = Dimensions.get('window').height;
class MainScreen extends Component {
state = {
computerPressed: false,
teamPressed: false
}
componentWillMount() {
this.slide1 = new Animated.Value(0);
this.slide2 = new Animated.Value(0);
this.bnt1();
this.bnt2();
}
bnt1() {
Animated.timing(
this.slide1, {
delay: 100,
toValue: w / 1.161,
duration: 300,
}
).start();
}
bnt2() {
Animated.timing(
this.slide2, {
delay: 300,
toValue: w / 1.161,
duration: 300,
}
).start();
}
render() {
return (
<Image
source={require('./Images/bg_img.png')}
style={styles.backgroundStyle} >
<StatusBar hidden />
<Image
source={require('./Images/History.png')}
style={styles.historybuttonStyle} />
<Image
source={require('./Images/logo_ws.png')}
style={styles.logoStyle} />
<TouchableWithoutFeedback
onPress={() => {
btnSound.play();
Actions.screen2({ challenge: 'Computer' });
}
}
onPressIn={() => {
this.setState({ computerPressed: true });
}
}
onPressOut={() => {
this.setState({ computerPressed: false });
}
} >
<Animated.Image
source={this.state.computerPressed ? a : b}
style={[styles.landingbnt1Style, { transform: [{ translateX: this.slide1 }] }]} />
</TouchableWithoutFeedback>
<TouchableWithoutFeedback
onPress={() => {
Actions.screen2({ challenge: 'Team' });
}
}
onPressIn={() => {
this.setState({ teamPressed: true });
}
}
onPressOut={() => {
this.setState({ teamPressed: false });
}
} >
<Animated.Image
source={this.state.teamPressed ? c : d}
style={[styles.landingbnt2Style, { transform: [{ translateX: this.slide2 }] }]} />
</TouchableWithoutFeedback>
</Image>
);
}
}
const styles = {
backgroundStyle: {
flex: 1,
width: w,
height: h,
flexWrap: 'wrap',
position: 'relative'
},
logoStyle: {
width: w,
height: h,
resizeMode: 'contain',
position: 'absolute',
bottom: h / 15
},
historybuttonStyle: {
width: w / 7.5,
height: h / 14,
right: (w / 20),
top: (h / 40),
position: 'absolute'
},
landingbnt1Style: {
width: w / 1.44,
height: h / 13.14,
top: h / 1.41,
left: -(w / 1.44)
},
landingbnt2Style: {
width: w / 1.44,
height: h / 13.14,
top: h / 1.35,
left: -(w / 1.44)
}
};
export default MainScreen;
It may not be the correct way of using react-native-sound it is because i couldnt find an example it would be better I someone also share their codes using react-native-sound
You can't load the sound from any directories. You have to Save your sound clip files under the directory android/app/src/main/res/raw for android and for ios Open Xcode and add your sound files to the project (Right-click the project and select Add Files to [PROJECTNAME])
You can find the detail docs for this at the link below :-
Basic Usage
and for theworking example for this you can check code in the link below :-
Example demo
I hope this is what you are looking for :)

.setState is not a function in React Native

I've looked through many other threads with this same issue, but none seem to have the solution I'm looking for. I followed a tutorial off of YouTube (Fullstack Development is the channel, and it is how to make a game in 28 minutes). My main code looks like this:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Dimensions,
Animated,
Image,
} from 'react-native';
import Enemy from './app/components/Enemy';
export default class Blox extends Component {
constructor(props){
super(props);
this.state = {
movePlayerVal: new Animated.Value(40),
playerSide:'left',
points: 0,
moveEnemyVal: new Animated.Value(0),
enemyStartposX: 0,
enemySide: 'left',
enemySpeed: 4200,
gameOver: false,
};
}
render() {
return (
<Image source = {require('./app/img/bg.png')} style={styles.container}>
<View style= {{ flex:1, alignItems: 'center', marginTop: 80 }}>
<View style={styles.points}>
<Text style={{ fontWeight: 'bold', fontSize: 40 }}>{this.state.points}</Text>
</View>
</View>
<Animated.Image source={require('./app/img/car.png')}
style = {{
height:100,
width:100,
position:'absolute',
zIndex:1,
bottom: 50,
resizeMode: 'stretch',
transform: [
{ translateX: this.state.movePlayerVal }
]
}}></Animated.Image>
<Enemy enemyImg={require('./app/img/enemy.png')}
enemyStartposX={this.state.enemyStartposX}
moveEnemyVal={this.state.moveEnemyVal} />
<View style={styles.controls}>
<Text style = {styles.left} onPress={ () => this.movePlayer('left') }> {'<'} </Text>
<Text style={styles.right} onPress={ () => this.movePlayer('right') }> {'>'} </Text>
</View>
</Image>
);
}
movePlayer(direction) {
//move player right
if (direction == 'right') {
this.setState({ playerSide: 'right' }); //issue with setState being used as a function (from lines 78-124)
Animated.spring(
this.state.movePlayerVal,
{
toValue: Dimensions.get('window').width = 140,
tension: 120,
}
).start();
} else if (direction == 'left') {
this.setState({ playerSide: 'left' });
Animated.spring(
this.state.movePlayerVal,
{
toValue: 40,
tension: 120,
}
).start();
}
}
componentDidMount() {
this.animateEnemy();
}
animateEnemy() {
this.state.moveEnemyVal.setValue(-100);
var windowH = Dimensions.get('window').height;
//Generate left distance for enemy
var r = Math.floor(Math.random() * 2) * 1;
if (r == 2) {
r = 40;
this.setState({ enemySide: 'left' });
} else {
r = Dimensions.get('window').width = 140;
//Enemy is on the right
this.setState = ({ enemySide: 'right' });
}
this.setState({ enemyStartposX: r }); //issue with this
//Interval to check for collision each 50 ms
var refreshIntervalId;
refreshIntervalId = ( () => {
//Collision logic
//If enemy collides with player and they are on the same side
//and the enemy has not passed the player safely
if (this.state.moveEnemyVal._value > windowH - 280 && this.state.moveEnemyVal._value < windowH -180 && this.state.playerSide == this.state.enemySide) {
clearInterval(refreshIntervalId)
this.setState({ gameOver: true });
this.gameOver();
}
}, 50);
//Increase enemy speed each 20th second
setInterval ( () => {
this.setState({ enemySpeed: this.state.enemySpeed - 50 })
}, 20000);
//Animate the enemy
Animated.timing(
this.state.moveEnemyVal,
{
toValue: Dimensions.get('window').height,
duration: this.state.enemySpeed,
}
).start(event => {
//if no enemy collision is detected, restart enemy animation
if (event.finished && this.state.gameOver == false) {
clearInterval(refreshIntervalId);
this.setState({ points: ++this.state.points });
this.animateEnemy();
}
});
}
gameOver() {
alert('You lost big time!');
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
position: 'relative',
resizeMode: 'cover',
},
points: {
width: 80,
height: 80,
backgroundColor: '#fff',
borderRadius: 100,
alignItems: 'center',
justifyContent: 'center',
},
controls: {
alignItems: 'center',
flexDirection: 'row',
},
right: {
flex: 1,
color: '#fff',
margin: 0,
fontSize: 60,
fontWeight: 'bold',
textAlign: 'left'
},
left: {
flex: 1,
color: '#fff',
fontSize: 60,
fontWeight: 'bold',
textAlign: 'right'
},
});
I also have an enemy class that looks like this:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Animated,
Image,
} from 'react-native';
export default class Enemy extends Component {
render() {
return (
<Animated.Image source={this.props.enemyImg}
style = {{
height:100,
width:100,
position:'absolute',
resizeMode: 'stretch',
left: this.props.enemyStartposX,
transform: [
{ translateY: this.props.moveEnemyVal },
]
}}></Animated.Image>
);
}
}
I'm running this through Expo XDE, and as I was building it, it worked. However, once I started coding the animation, Expo turned red and said I had an error in line 124 (in App.js), that .setState is not a function, it is an object. I commented it out, and it told me I had the same error in line 78 of my App.js file. Can you tell me what .setState is, and how to potentially fix this error? Thanks.
You have a wrong setState call in your animateEnemy function. That's why you got that error message.
animateEnemy() {
...
if (r == 2) {
r = 40;
this.setState({ enemySide: 'left' });
} else {
r = Dimensions.get('window').width = 140;
// Enemy is on the right
// this.setState = ({ enemySide: 'right' }); // This is wrong
this.setState({ enemySide: 'right' });
}
...
}
And it would be much better if you change all of the function with arrow function animateEnemy = () => { ... }. With this way, you don't need to manually bind it in the constructor.
You should bind the movePlayer function to the proper scope in your constructor:
constructor() {
this.movePlayer = this.movePlayer.bind(this);
}
I think your problem is how you handle the method callback. You just bind method movePlayer() and animateEnemy() in constructor like :
constructor(props) {
super(props);
this.state = {
movePlayerVal: new Animated.Value(40),
playerSide:'left',
points: 0,
moveEnemyVal: new Animated.Value(0),
enemyStartposX: 0,
enemySide: 'left',
enemySpeed: 4200,
gameOver: false,
};
// This binding is necessary to make `this` work in the callback
this.movePlayer = this.movePlayer.bind(this);
this.animateEnemy = this.animateEnemy.bind(this);
}
maybe you can learn deeply about how your handle method in ReactNative in this.
i hope my answer can help you..

The spin animation set on the image is not working in react-native

I am trying to spin an Image it is basically to show that a coin is flipped ( coin Tossing animation ) I have applied this basic animation to the image but it is not getting animated,
The image is stationary while I tested it on emulator
this is my index.android.js file :
import React, { Component } from 'react';
import {
AppRegistry,
View,
Animated,
Easing
} from 'react-native';
export default class animateTest extends Component {
constructor(props) {
super(props);
this.spinValue = new Animated.Value(0);
}
spin() {
this.spinValue.setValue(0);
Animated.timing(
this.spinValue, {
toValue: 1,
duration: 1500,
useNativeDriver: true,
easing: Easing.linear
}
).start();
}
render() {
const spin = this.spinValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
});
return (
<View style={styles.ViewStyle}>
<Animated.Image
style={[
styles.coinStyle,
{
transform: [
{ rotate: spin }
]
}
]}
source={require('./Images/Coin_Tail.png')}
style={styles.coinStyle} />
</View>
);
}
}
const styles = {
coinStyle: {
width: 150,
height: 150,
},
ViewStyle: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black'
}
};
AppRegistry.registerComponent('animateTest', () => animateTest);
You code have 2 issues:
1) In your render function, you have a duplicated style prop for your image that override the first style with transform styling. To fix it, remove the second style prop
2) Your code did not trigger the spin animation, you can add a touchable with on press event to call your spin method. For quick test, you can add
componentDidMount() {
this.spin();
}

React Native: How do you animate the rotation of an Image?

Rotation is a style transform and in RN, you can rotate things like this
render() {
return (
<View style={{transform:[{rotate: '10 deg'}]}}>
<Image source={require('./logo.png')} />
</View>
);
}
However, to animate things in RN, you have to use numbers, not strings. Can you still animate transforms in RN or do I have to come up with some kind of sprite sheet and change the Image src at some fps?
You can actually animate strings using the interpolate method. interpolate takes a range of values, typically 0 to 1 works well for most things, and interpolates them into a range of values (these could be strings, numbers, even functions that return a value).
What you would do is take an existing Animated value and pass it through the interpolate function like this:
spinValue = new Animated.Value(0);
// First set up animation
Animated.timing(
this.spinValue,
{
toValue: 1,
duration: 3000,
easing: Easing.linear, // Easing is an additional import from react-native
useNativeDriver: true // To make use of native driver for performance
}
).start()
// Next, interpolate beginning and end values (in this case 0 and 1)
const spin = this.spinValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
Then use it in your component like this:
<Animated.Image
style={{transform: [{rotate: spin}] }}
source={{uri: 'somesource.png'}} />
In case if you want to do the rotation in loop, then add the Animated.timing in the Animated.loop
Animated.loop(
Animated.timing(
this.spinValue,
{
toValue: 1,
duration: 3000,
easing: Easing.linear,
useNativeDriver: true
}
)
).start();
Don't forget to add property useNativeDriver to ensure that you get the best performance out of this animation:
// First set up animation
Animated.timing(
this.state.spinValue,
{
toValue: 1,
duration: 3000,
easing: Easing.linear,
useNativeDriver: true
}
).start();
A note for the newbies like me:
For animating something else you need to wrap it in <Animated.SOMETHING> for this to work. Or else the compiler will panic on that transform property:
import {Animated} from 'react-native';
...
//animation code above
...
<Animated.View style={{transform: [{rotate: spinValue}] }} >
<YourComponent />
</Animated.View>
BUT for an image (Animated.Image), the example above is 100% goodness and correct.
Since most of the answers are functions & hooks based, herewith a complete example of class based Animation of Image.
import React from 'react';
import {
SafeAreaView,
View,
Animated,
Easing,
TouchableHighlight,
Text,
} from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
rotateValueHolder: new Animated.Value(0)
};
}
componentDidMount = () => {
this.startImageRotateFunction();
}
startImageRotateFunction = () => {
Animated.loop(Animated.timing(this.state.rotateValueHolder, {
toValue: 1,
duration: 3000,
easing: Easing.linear,
useNativeDriver: false,
})).start();
};
render(){
return(
<SafeAreaView>
<View>
<Animated.Image
style={{
width: 200,
height: 200,
alignSelf:"center",
transform:
[
{
rotate: this.state.rotateValueHolder.interpolate(
{
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
}
)
}
],
}}
source={{uri:'https://raw.githubusercontent.com/AboutReact/sampleresource/master/old_logo.png',}}
/>
<TouchableHighlight
onPress={() => this.startImageRotateFunction()}>
<Text style={{textAlign:"center"}}>
CLICK HERE
</Text>
</TouchableHighlight>
</View>
</SafeAreaView>
);
}
}
Just gonna drop the solution I solved by stitching together parts from the answers here.
import { Feather } from '#expo/vector-icons'
import * as React from 'react'
import { TextStyle, Animated, Easing } from 'react-native'
import { Colors, FontSize } from '~/constants/Theme'
export const LoadingSpinner = React.memo(
({ color = Colors['sand'], size = FontSize['md'] - 1, fadeInDelay = 1000, ...props }: Props) => {
const fadeInValue = new Animated.Value(0)
const spinValue = new Animated.Value(0)
Animated.sequence([
Animated.delay(fadeInDelay),
Animated.timing(fadeInValue, {
toValue: 1,
duration: 1500,
easing: Easing.linear,
useNativeDriver: true,
}),
]).start()
Animated.loop(
Animated.timing(spinValue, {
toValue: 360,
duration: 300000,
easing: Easing.linear,
useNativeDriver: true,
})
).start()
return (
<Animated.View
style={{
opacity: fadeInValue,
transform: [{ rotate: spinValue }],
}}
>
<Feather
name="loader"
size={size}
style={{
color,
alignSelf: 'center',
}}
{...props.featherProps}
/>
</Animated.View>
)
}
)
type Props = {
color?: TextStyle['color']
size?: number
featherProps?: Partial<Omit<React.ComponentProps<typeof Feather>, 'style'>>
fadeInDelay?: number
}
Hope it helps 👍

Categories

Resources