Skip to content

Instantly share code, notes, and snippets.

@osdnk

osdnk/sample.js Secret

Last active February 2, 2020 22:42
Show Gist options
  • Save osdnk/4a5b3d2237c4c4558c8d3280a50eb118 to your computer and use it in GitHub Desktop.
Save osdnk/4a5b3d2237c4c4558c8d3280a50eb118 to your computer and use it in GitHub Desktop.
import Animated, { Easing } from "react-native-reanimated";
import Modal from "react-native-modal";
import React, { PureComponent } from "react";
import {
State as GestureState,
LongPressGestureHandler,
PanGestureHandler,
} from "react-native-gesture-handler";
import { StyleSheet, Text, Button, View } from "react-native";
const ACTIVATION_RANGE = [-40, 40];
const {
Value,
and,
debug,
add,
block: animationBlock,
call,
cond: condition,
divide,
eq,
event,
multiply,
round,
set,
timing,
} = Animated;
const colors = ['red', 'green', 'blue']
const timingAnimationConfig = (duration, toValue) => ({
duration,
toValue,
easing: Easing.inOut(Easing.ease),
});
export default class Block extends PureComponent {
constructor(props) {
super(props);
this.state = {
animating: false,
modalVisible: false,
verticalScrollOffset: 0,
};
this.panRef = React.createRef();
this.longPressRef = React.createRef();
this.opacity = new Value(1);
this.X = new Value(0);
this.Y = new Value(0);
this.offsetY = 0;
this.offsetX = 0;
this.createPanHandler();
}
componentDidMount = () => {
this.blockContainer.setNativeProps({ style: { borderLeftColor: "green" } });
};
_wasCalled = new Animated.Value(0)
createPanHandler = () => {
this.panHandler = event([
{
nativeEvent: ({ translationX: x, translationY: y, state }) =>
animationBlock([
debug("d", eq(state, GestureState.ACTIVE)),
condition(eq(state, GestureState.ACTIVE), [
set(this._wasCalled, 0),
set(this.Y, add(y, this.offsetY)),
debug("m", eq(state, GestureState.ACTIVE)),
call([this.Y], this.handleVerticalChange),
set(this.X, multiply(round(divide(add(x, 80)), 80))),
call([this.X], this.handleHorizontalChange),
]),
condition(and(eq(state, GestureState.END), eq(this._wasCalled, 0)), [
set(this._wasCalled, 1),
call([], this.showModal),
])
])
},
]);
};
handleHorizontalChange = value => {
this.horizontalOffset = value[0];
const borderLeftColor = colors[Math.floor(value[0] / 80) % 3]
this.blockContainer.setNativeProps({ style: { borderLeftColor } });
};
handleVerticalChange = value => {
if (!this.state.animating) {
this.verticalOffset = value[0];
}
};
undoDragging = () => {
// This forces rerender and not denies queued animations.
timing(this.X, timingAnimationConfig(300, 0)).start();
timing(this.Y, timingAnimationConfig(300, 0)).start(() => {
setTimeout(() => {
this.blockContainer.setNativeProps({ style: { borderLeftColor: "green" } });
this.setState({ animating: false });
}, 300)
});
timing(this.opacity, timingAnimationConfig(250, 1)).start();
}
handleLongStateChange = ({ nativeEvent }) => {
if (nativeEvent.state === GestureState.ACTIVE) {
timing(this.opacity, timingAnimationConfig(200, 0.4)).start();
}
if (nativeEvent.state === GestureState.END) {
timing(this.opacity, timingAnimationConfig(200, 1)).start();
}
};
showModal = () => {
this.setState({ modalVisible: true });
};
cancel = () => {
this.setState({ modalVisible: false });
this.undoDragging();
};
render() {
const { modalVisible, verticalScrollOffset } = this.state;
return (
<View>
<PanGestureHandler
activeOffsetX={ACTIVATION_RANGE}
activeOffsetY={ACTIVATION_RANGE}
onGestureEvent={this.panHandler}
onHandlerStateChange={this.panHandler}
ref={this.panRef}
simultaneousHandlers={this.longPressRef}
>
<Animated.View
style={[
styles.blockContainer,
{
transform: [
{ translateY: verticalScrollOffset },
{ translateY: this.Y },
{ translateX: this.X },
],
width: 80,
},
]}
>
<LongPressGestureHandler
minDurationMs={250}
onHandlerStateChange={this.handleLongStateChange}
ref={this.longPressRef}
>
<Animated.View
ref={ref => (this.blockContainer = ref)}
style={[
styles.block,
{
height: 100,
width: 80,
opacity: this.opacity,
},
]}
>
<View style={styles.blockContent}>
<Text>Grab</Text>
</View>
</Animated.View>
</LongPressGestureHandler>
</Animated.View>
</PanGestureHandler>
<Modal isVisible={modalVisible}>
<View style={styles.modal}>
<Button title="Undo Animation :)" onPress={this.cancel}>
</Button>
</View>
</Modal>
</View>
);
}
}
const styles = StyleSheet.create({
blockContainer: {
position: "absolute",
right: 7,
},
modal: {
flex: 1,
},
block: {
backgroundColor: "white",
borderTopColor: "gray",
borderRightColor: "gray",
borderBottomColor: "gray",
borderLeftColor: "gray",
borderWidth: StyleSheet.hairlineWidth,
borderLeftWidth: 4,
borderTopRightRadius: 10,
borderBottomRightRadius: 10,
padding: 5,
shadowColor: "black",
shadowOffset: { width: 2, height: 1 },
shadowOpacity: 0.5,
shadowRadius: 2,
},
blockContent: {
overflow: "hidden",
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment