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 es 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 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 es 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>
Share
Improve this question
asked Feb 4, 2020 at 2:34
Evgenii KlepilinEvgenii Klepilin
6952 gold badges8 silver badges21 bronze badges
6
- 1 This is what you are looking for – CampbellMG Commented Feb 4, 2020 at 4:56
- @CampbellMG I have seen that one, and it looked like an OK solution, but not the best. But I appreciate pointing that example out – Evgenii Klepilin Commented Feb 4, 2020 at 7:59
- What part of this solution doesn't work for you? – CampbellMG Commented Feb 4, 2020 at 8:00
-
What I don't like about this solution is that it is possible to approximate it down to the circular movement, but not to provide exact functional correlation. There is a variable
snapshot
which defines how many frames would you want to have in your animation. What I was hoping finding would be the proper interpolation of a value that would result in a continuous graph/movement – Evgenii Klepilin Commented Feb 4, 2020 at 8:03 -
1
The problem you are going to run into trying to create circular movement with the
Animated
API is that you only have access to basic mathematical functions (add, divide, modulo etc.). That is why this solution samples values along a circular path rather than an exact figure. You could try a library like this that includes a few more plex functions like sin using a Taylor Series. – CampbellMG Commented Feb 4, 2020 at 8:14
2 Answers
Reset to default 2I 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});
}
ponentDidMount() {
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);
}
ponentWillMount(): 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.