How to have a heart beat animation with React native? - react-native

I'm learning React native and I would like to have heart beat animation
I did that but it's not the good result, I would like to have heart beat.
If someone can help me it's would be very nice thanks a lot
import React, { PureComponent } from "react";
import { Animated, StyleSheet, Text, View } from "react-native";
export class Loading extends PureComponent {
constructor(props: any) {
super(props);
this.state = {
opacity: new Animated.Value(0),
};
}
public componentDidMount() {
Animated.timing(
this.state.opacity,
{
toValue: 100,
duration: 5000,
},
).start();
}
public render() {
return (
<View>
<View>
<Animated.View
style={[styles.animation, {
opacity: this.state.opacity,
transform: [
{
scale: this.state.opacity.interpolate({
inputRange: [0.5, 1],
outputRange: [1, 0.95],
}),
}]},
]}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
animation: {
backgroundColor: "red,
width: 100,
height: 100,
borderRadius: 50,
},
});

A bit late but here is my own heartbeat animation made with React Native's Animated module:
export const HeartbeatAnimation = (
value: Animated.Value,
minValue: number,
maxValue: number
) =>
Animated.loop(
Animated.sequence([
Animated.timing(value, {
toValue: maxValue,
duration: 100
}),
Animated.timing(value, {
toValue: minValue,
duration: 100
}),
Animated.timing(value, {
toValue: maxValue,
duration: 100
}),
Animated.timing(value, {
toValue: minValue,
duration: 2000
})
])
);
Try playing with the minValue and maxValue to get your favorite animation !

As you say you are new to react native, I would like to suggest you use a react-native-animatable library which is very helpful with some built-in animation and custom animation.
Here is a link of GitHub https://github.com/oblador/react-native-animatable for your solution which I mentioned below.
In this page, you can find different methods for how to use animatable library for animation in react-native.
Now as per your question here is a solution
you have to install react-native-animatable by
$ npm install react-native-animatable --save
Step 1:
import * as Animatable from 'react-native-animatable';
Step 2: Use this code
<Animatable.Text
animation="pulse"
easing="ease-out"
iterationCount="infinite"
style={{ textAlign: 'center' }}>
❤️
</Animatable.Text>

you can use Animated.loop like this
useEffect(() => {
// makes the sequence loop
Animated.loop(
// runs given animations in a sequence
Animated.sequence([
// increase size
Animated.timing(anim.current, {
toValue: 10,
duration: 2000,
}),
// decrease size
Animated.timing(anim.current, {
toValue: 1,
duration: 2000,
}),
])
).start();
}, []);
Check below the full code and Live preview in Snack.
import React, { useRef, useEffect } from 'react';
import { Text, View, StyleSheet, Animated } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
export default function App() {
const anim = useRef(new Animated.Value(1));
useEffect(() => {
// makes the sequence loop
Animated.loop(
// runs given animations in a sequence
Animated.sequence([
// increase size
Animated.timing(anim.current, {
toValue: 10,
duration: 2000,
}),
// decrease size
Animated.timing(anim.current, {
toValue: 1,
duration: 2000,
}),
])
).start();
}, []);
return (
<View style={styles.container}>
<Animated.View style={{ transform: [{ scale: anim.current }] }}>
<Ionicons name="md-heart" size={32} color="red" />
</Animated.View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgb(254, 254, 254)',
padding: 8,
},
});

You can give React Native Lottie a go for a more flexible and appealing animation.
To get started, install it via:
Step 1: > npm i --save lottie-react-native#2.5.11
Step 2: > react-native link lottie-react-native
Step 3 : Go to Lottie Files, which is a collection of awesome animations done by the community. Search and choose a heartanimation that suits you and download the .jsonfile associated with it. Then proceed to render it as shown below:
import LottieView from 'lottie-react-native';
render() {
return (
<LottieView
ref={animation => {
this.animation = animation;
}}
source={require('../path/to/animation.json')}
/>
);
}
PS: I think This heart beat animation can fit your need. You can edit it's color and speed and then proceed to download it and use it in your app.

Use react-native-animatable:
<Animatable.Text
animation="pulse"
easing="ease-out"
iterationCount="infinite"
style={{ ... }}>❤️</Animatable.Text>
or...
<Animatable.View
animation="pulse"
easing="ease-out"
iterationCount="infinite"
style={{ ... }}>{children}</Animatable.View>

You can achieve that with react-native-animatable by creating your custom pulse animation:
const pulse = {
0: {
scale: 1,
},
0.5: {
scale: 1.5
},
1: {
scale: 1
}
}
Then, in your Animatable.View
<Animatable.View
animation={pulse}
easing="ease-out"
iterationCount="infinite"
>
<Text>PULSE ME</Text>
</Animatable.View>

Related

Smooth rotation of React Native SVG Component [duplicate]

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 👍

Error while animating rotateX in react native

I am trying to rotate an icon on press of a button in my react native application.
But I am getting this error:
Error while updating property 'transform' of a view managed by:
RCTView
This is the Icon itself:
<TouchableOpacity
style={[
styles.expandButton,
{transform: [{rotateX: toString(expandIconAngle) + 'deg'}]},
]}
onPress={() => {
rotateIcon();
}}>
<Icon name="expand-less" color="#ffffff" size={28} />
</TouchableOpacity>
This is the function which is responsible for rotating the icon:
const expandIconAngle = useRef(new Animated.Value(0)).current;
function rotateIcon() {
Animated.timing(expandIconAngle, {
toValue: 180,
duration: 300,
easing: Easing.linear,
}).start();
}
Where am I going wrong?
use interpolate and Animated.Image :
import React, { useRef } from "react";
import { Animated, Text, View, StyleSheet, Button, SafeAreaView,Easing,TouchableOpacity } from "react-native";
const App = () => {
// fadeAnim will be used as the value for opacity. Initial Value: 0
const angle = useRef(new Animated.Value(0)).current;
const fadeOut = () => {
// Will change fadeAnim value to 0 in 3 seconds
Animated.timing(
angle,
{
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()
};
const spin =angle.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
return (
<SafeAreaView style={styles.container}>
<Animated.Image
style={{transform: [{rotateX: spin}] }}
source={require('#expo/snack-static/react-native-logo.png')} />
<TouchableOpacity onPress={fadeOut} style={styles.buttonRow}>
<Text>Button</Text>
</TouchableOpacity>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
buttonRow: {
flexBasis: 100,
justifyContent: "space-evenly",
marginVertical: 16
}
});
export default App;
LIVE example - https://snack.expo.dev/TP-fQExXT

Slide up down animation in the react native

I am using animation for up and down in the react native, But the animation just slide from up to down and then stop at the bottom i want to move it up and down continuously. I have also used animation loop so please check and provide me solution for this
import React, { useEffect, useState } from 'react'
import { Text, View, Animated, Easing, StyleSheet } from 'react-native'
import LoaderLogo from '../../icons/commonicons/LoaderLogo'
import { Loadericon } from '../../constants/Image';
import LinearGradient from 'react-native-linear-gradient';
import { dynamicSize } from '../sizechoose';
const amimationScreen = () => {
const startValue = new Animated.Value(0);
const endValue = dynamicSize(225);
const startValue2 = new Animated.Value(225);
const endValue2 = dynamicSize(0);
const duration = 5000;
useEffect(() => {
Animated.sequence([
Animated.timing(startValue, {
toValue: endValue,
duration: duration,
useNativeDriver: true,
}),
Animated.timing(startValue2, {
toValue: endValue2,
duration: duration,
useNativeDriver: true,
})
]).start()
}, [startValue, endValue, duration]);
return (
<Animated.View style={[{ transform: [{ translateY: startValue }] }]}>
<View style={{backgroundColor:'red',height:10,width:100}}>
</View>
</Animated.View>
)
}
export default amimationScreen
I also tried with react-native-animatable package but it is not good to use for me as it starts animation from the top of the screen.
This worked for me:
const App = () => {
const animated = new Animated.Value(0);
const duration = 5000;
useEffect(() => {
Animated.loop(
Animated.sequence([
Animated.timing(animated, {
toValue: 255,
duration: duration,
useNativeDriver: true,
}),
Animated.timing(animated, {
toValue: 0,
duration: duration,
useNativeDriver: true,
}),
]),
).start();
}, []);
return (
<Animated.View style={[{transform: [{translateY: animated}]}]}>
<View style={{backgroundColor: 'red', height: 10, width: 100}}></View>
</Animated.View>
);
};
So instead of having two instances of Animated.Value for translation, create one and let it transition from 0 to 255 and from 255 back to 0 in sequence. And make it loop once the sequence has finished.
I think the main problem in your original approach is that startValue decides how the view translates since this is what you pass as the value of translateY. The downward animation therefore happens correctly in your example. The upward animation however does not happen, because startValue2 is passed to Animated.timing and startValue is not used in the translation of any views in your example.
import React, { useEffect, useRef, useState } from 'react';
import { Animated, Dimensions, Easing, StyleSheet, View } from 'react-native';
export const App = () => {
const animatedValue = useRef(new Animated.Value(0)).current;
const [isTop, setIsTop] = useState(true);
const startAnimation = toValue => {
Animated.timing(animatedValue, {
toValue,
duration: 1000,
easing: Easing.linear,
useNativeDriver: true
}).start(() => {
setIsTop(!isTop);
})
}
useEffect(() => {
startAnimation(isTop ? 1 : 0);
}, [isTop]);
const translateY = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, Dimensions.get('window').height - 70],
extrapolate: 'clamp'
})
return (
<View style={styles.container}>
<Animated.View style={[styles.square, { transform: [{ translateY }] }]}>
</Animated.View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center'
},
square: {
width: 70,
height: 70,
backgroundColor: 'red'
}
});

Simple animation in react-native: moving an image from left to right

Can anyone share a code example for a react-native animation that moves an image from left to right, then move back to the starting point and repeat the motion?
Update:
The answer below helped a lot, but it didn't work. I used it to create the following animation that moves an image from left to right (I am using RN 0.62.2).
import React from 'react'
import { StyleSheet, View, Animated, Easing } from 'react-native';
const test = require('../images/test.png');
export class Splash extends React.Component {
constructor(props) {
super(props);
this.state = { xValue: new Animated.Value(-100) }
}
moveLR = () => {
Animated.timing(
this.state.xValue,
{
toValue: 100,
duration: 1000, // the duration of the animation
easing: Easing.linear, // the style of animation
useNativeDriver: true
}
).start();
}
moveRL = () => {
Animated.timing(
this.state.xValue,
{
toValue: -100,
duration: 3000, // the duration of the animation
easing: Easing.linear, // the style of animation
useNativeDriver: true
}
).start();
}
componentDidMount = () => {
this.moveLR();
}
render = () => {
return (
<View style={styles.mainContainer}>
<Animated.Image
style={{ width: 170, height: 146 }}
source={test}
style={{ width: 170, height: 146,
transform: [{ translateX: this.state.xValue }] }}>
</Animated.Image>
</View>
)
}
}
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
animationView: {
backgroundColor: 'red',
width: 100,
height: 100
}
})
Update by Yossi:
The code below didn't work for me in RN 0.62.2. I am accepting the answer, but I modified it and the code that is working is included now in the question.
Original answer:
Before getting started, I need to introduce you to the two types of values ​​for Animated animations:
Animated.Value () where we define a value, useful when we want to move an element on a single axis (X or Y), change the size of an element, etc. This is what we will use here, in this chapter, and this is what is used the most.
Animated.ValueXY () where we define a vector, useful for moving an element on two axes.
With these values, we can define several types of Animated animations. We will discover them one by one, testing them each time. in this example, I will only talk about Animated.timing ()
Here you can see an example of code which is gonna moove a red box from left to right and stop when the user decides, you can try it and tell if it worked for you :
// Test.js
import React from 'react'
import { StyleSheet, View, Animated, TouchableOpacity, Text, Easing } from 'react-native'
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
leftPosition : new Animated.Value (0)
}
this.mooveLR = this.mooveLR.bind(this);
this.mooveRL = this.mooveRL.bind(this);
this.stopAnimation = this.stopAnimation.bind(this);
}
stopAnimation () {
this.setState({
leftPosition : this.state.leftPosition // this forces the left position to remain the same considering the `componentDidMount` method already happened
})
}
mooveLR (){
Animated.timing(
this.state.leftPosition,
{
toValue: 100,
duration: 3000, // the duration of the animation
easing: Easing.linear, // the style of animation
}
).start() // starts this annimation once this method is called
}
mooveRL (){
Animated.timing(
this.state.leftPosition,
{
toValue: 0,
duration: 3000, // the duration of the animation
easing: Easing.linear, // the style of animation
}
).start() // starts this annimation once this method is called
}
componentDidMount(){
this.state.leftPosition === 0 ? this.mooveLR () : this.mooveRL () // repeats always when the red box return to its initial position : leftPosition === 0
}
render() {
return (
<View style={styles.main_container}>
<Animated.View style={[styles.animation_view, {left : this.state.leftPosition}]}>
</Animated.View>
<TouchableOpacity onPress = { () => this.stopAnimation ()}>
<Text>Stop animation</Text>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
animation_view: {
backgroundColor: 'red',
width: 100,
height: 100
}
})
export default Test;
Hope it's gonna help
Regards
I have resolved this issue by doing:
import {
Easing
} from 'react-native';
Since I prefer using react hooks, I converted the solution Provided by #pacy.eth, and here it is for anyone who prefers to use react hooks.
import { View, Text, Animated, Easing } from 'react-native';
import React, { useEffect, useState } from 'react';
const Animate= ({ children, left, leftP, duration }) => {
const [leftPosition, setLeftPosition] = useState(new Animated.Value (leftP));
useEffect(() => {
left ? mooveLR() : mooveRL();
}, []);
const mooveLR = () => {
Animated.timing(leftPosition, {
toValue: 100,
duration, // the duration of the animation
easing: Easing.linear, // the style of animation
}).start(); // starts this annimation once this method is called
};
const mooveRL = () => {
Animated.timing(leftPosition, {
toValue: 0,
duration, // the duration of the animation
easing: Easing.linear, // the style of animation
}).start(); // starts this annimation once this method is called
};
return (
<Animated.View style={[{ left: leftPosition }]}>{children}</Animated.View>
);
};
export default Animate;
And with a little modifications, I made it reusable in severals ways:
one of my favorite ways, is by wrapping the component that I want to animate and I pass the the direction "left: true or false" I set the "leftP" which is the leftPosition (in my case I am hiding the view and with a click of a button I slide it in with the Animate component created) and the "duration" of the animation.
for ex:
<Animate left={false} duration={1000} leftP={-Dimensions.get('window').width}>
...
</Animate>

Multiple drag and drop simultaneous in React Native

Hello i'm creating a game in react native and i'm stuck because i wan't both players can drag and drop horizontaly an element in same time on the same phone.
I have two components like that:
export class Player1 extends Component{
constructor(props){
super(props);
this.state = {
pan : new Animated.ValueXY()
};
}
componentWillMount(){
this.panResponder = PanResponder.create({
onMoveShouldSetResponderCapture : () => true,
onMoveShouldSetPanResponderCapture : () => true,
onPanResponderGrant : (e, gestureState) => {
this.state.pan.setOffset({x: this.state.pan.x._value, y: this.state.pan.y._value});
this.state.pan.setValue({x: 0, y: 0});
},
onPanResponderMove : Animated.event([null,{
dx : this.state.pan.x,
}]),
onPanResponderRelease: (e, {vx, vy}) => {
}
});
}
render(){
return (
<View style={styles.mainContainer}>
{this.renderDraggable()}
</View>
);
}
renderDraggable(){
return (
<View style={styles.draggableContainer}>
<Animated.View
style={[this.state.pan.getLayout(), styles.triangle]}
{...this.panResponder.panHandlers} >
</Animated.View>
</View>
);
}
}
And in my screen i call my components like that:
export default function HomeScreen() {
return (
<View>
<Player1></Player1>
<Player2></Player2>
</View>
);
}
Thanks for your help
I found a solution, i used react-native-gesture-handle like in the directory doubleDraggable of the example: https://kmagiera.github.io/react-native-gesture-handler/docs/example.html
My Code:
import React, { Component } from 'react';
import { Animated, StyleSheet, View } from 'react-native';
import {
PanGestureHandler,
ScrollView,
State,
} from 'react-native-gesture-handler';
export class Players extends Component {
constructor(props) {
super(props);
this._translateX = new Animated.Value(0);
this._translateY = new Animated.Value(0);
this._lastOffset = { x: 0, y: 0 };
this._onGestureEvent = Animated.event(
[
{
nativeEvent: {
translationX: this._translateX,
},
},
],
);
}
_onHandlerStateChange = event => {
if (event.nativeEvent.oldState === State.ACTIVE) {
this._lastOffset.x += event.nativeEvent.translationX;
this._translateX.setOffset(this._lastOffset.x);
this._translateX.setValue(0);
this._translateY.setOffset(this._lastOffset.y);
this._translateY.setValue(0);
}
};
render() {
return (
<PanGestureHandler
{...this.props}
onGestureEvent={this._onGestureEvent}
onHandlerStateChange={this._onHandlerStateChange}>
<Animated.View
style={[
styles.box,
{
transform: [
{ translateX: this._translateX },
{ translateY: this._translateY },
],
},
this.props.boxStyle,
]}
/>
</PanGestureHandler>
);
}
}
export default class Example extends Component {
render() {
return (
<View style={styles.scrollView}>
<DraggableBox />
</View>
);
}
}
const styles = StyleSheet.create({
scrollView: {
flex: 1,
},
box: {
position: 'absolute',
width: 0,
height: 0,
backgroundColor: 'transparent',
borderStyle: 'solid',
borderLeftWidth: 25,
borderRightWidth: 25,
borderBottomWidth: 50,
borderLeftColor: 'transparent',
borderRightColor: 'transparent',
},
});
And Screen:
<View styles={styles.container}>
<Players boxStyle={styles.player1}></Players>
<Players boxStyle={styles.player2}></Players>
</View>
I have been searching for something similar endlessly for a few days but I couldn't find these demos that react-native-gesture-handler provides. Thanks a lot for posting this here #Lillian Pacaud. Here is the link for several of their demos including the draggable component: https://snack.expo.dev/#adamgrzybowski/react-native-gesture-handler-demo
If you need any simultaneous presses/gesture/drags/etc... your best bet is to use react-native-gesture-handler because the native implementation of all touch/gesture-based components in react native don't allow for simultaneous interactions with each especially for Android.
I made a functional component that does the same thing as the accepted answer. Just pass whatever you want to be draggable as a child under the component. It can handle simultaneous drags as well like the accepted answer on both iOS and Android.
Example of using the draggable component:
import React from 'react';
import { View } from 'react-native';
import { DraggableTest } from '../components/test';
export default function Screen() {
return (
<View style={{ flex: 1 }}>
<DraggableTest>
<View
style={{ width: 150, height: 150, backgroundColor: 'lime' }}
/>
</DraggableTest>
</View>
);
}
The draggable component:
import React, { useRef } from 'react';
import { Animated, StyleSheet } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
export function DraggableTest({ children }) {
const pan = useRef(new Animated.ValueXY()).current;
const lastOffset = useRef({ x: 0, y: 0 }).current;
const onGestureEvent = Animated.event(
[{ nativeEvent: { translationX: pan.x, translationY: pan.y } }],
{ useNativeDriver: false },
);
const onHandlerStateChange = event => {
if (event.nativeEvent.oldState == State.ACTIVE) {
lastOffset.x += event.nativeEvent.translationX;
lastOffset.y += event.nativeEvent.translationY;
pan.setOffset({ x: lastOffset.x, y: lastOffset.y });
pan.setValue({ x: 0, y: 0 });
}
};
return (
<PanGestureHandler
onGestureEvent={onGestureEvent}
onHandlerStateChange={onHandlerStateChange}>
<Animated.View style={[pan.getLayout(), styles.animatedView]}>
{children}
</Animated.View>
</PanGestureHandler>
);
}
const styles = StyleSheet.create({
animatedView: {
position: 'absolute',
},
});