Skip to content

Instantly share code, notes, and snippets.

@bradbyte
Created June 4, 2018 10:44
Show Gist options
  • Save bradbyte/70a79dddc922215044071dc1ff7775e7 to your computer and use it in GitHub Desktop.
Save bradbyte/70a79dddc922215044071dc1ff7775e7 to your computer and use it in GitHub Desktop.
Draggable
import React, { Component } from 'react';
import {
PanResponder,
Animated,
StyleSheet
} from 'react-native';
export default class Draggable extends Component {
state = {
panY: new Animated.Value(0),
scale: new Animated.Value(1),
active: false
};
lastPosition = 0;
panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => !this.props.disabled,
onMoveShouldSetPanResponder: () => !this.props.disabled,
onShouldBlockNativeResponder: () => false,
onPanResponderGrant: e => {
e.persist();
},
onPanResponderMove: (e, gestureState) => {
if (!this.state.active) {
return;
}
this.handleMove(gestureState.dy);
},
onPanResponderRelease: (e, gestureState) => {
if (this.state.active) {
this.toggleActive(gestureState);
this.handleMove(0);
}
},
onPanResponderTerminationRequest: () => {
if (this.state.active) {
// If a view is active do not release responder.
return false;
}
return true;
},
onPanResponderTerminate: (e, gestureState) => {
// If responder terminated while dragging,
// deactivate the element and move to the initial location.
if (this.state.active) {
this.toggleActive(gestureState);
// if (shallowEqual(this.props.location, this._location)) {
// this._relocate(this.props.location);
// }
}
}
});
handleMove = moveDistancyY => {
// this.state.panY.setValue(moveDistancyY);
this.props.onMove(moveDistancyY);
const halfHeight = this.height / 2;
const positionsMoved = Math.floor((moveDistancyY - halfHeight) / this.height, 1) + 1;
if (positionsMoved !== this.lastPosition) {
this.props.onChangePosition(positionsMoved);
this.lastPosition = positionsMoved;
}
}
toggleActive = gestureState => {
if (this.props.disabled) {
return;
}
const callback = this.state.active ? this.props.onRelease : this.props.onActivate;
Animated.spring(this.state.scale, {
toValue: this.state.active ? 1 : 1.05,
friction: 3
}).start();
this.setState({ active: !this.state.active });
if (callback) {
callback(gestureState, this.state.panY);
}
}
setLayout = ({ nativeEvent }) => this.height = nativeEvent.layout.height;
render() {
const panStyle = {
transform: [{ translateY: this.state.panY }, { scale: this.state.scale }]
};
return (
<Animated.View {...this.panResponder.panHandlers} style={[panStyle, styles.base, this.state.active && styles.active]} onLayout={this.setLayout}>
{React.cloneElement(this.props.children, { onLongPress: this.toggleActive })}
</Animated.View>
);
}
}
const styles = StyleSheet.create({
base: {
position: 'absolute',
left: 0,
right: 0,
zIndex: -1
},
active: {
zIndex: 10000,
backgroundColor: 'red'
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment