Im trying to make two circles that can drag and drop with react-native.
I could have created one circle that can drag and drop, but dont know how with two circles individually.
here is the code for one circle that can drag and drop,
constructor(props){
super(props);
this.state = {
pan : new Animated.ValueXY() //Step 1
};
this.panResponder = PanResponder.create({ //Step 2
onStartShouldSetPanResponder : () => true,
onPanResponderMove : Animated.event([null,{ //Step 3
dx : this.state.pan.x,
dy : this.state.pan.y
}]),
onPanResponderRelease : (e, gesture) => {} //Step 4
});
}
and this is for image
renderDraggable(){
return (
Drag me!
);
}
Solved
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image, // we want to use an image
PanResponder, // we want to bring in the PanResponder system
Animated // we wil be using animated value
} from 'react-native';
export default class Tag extends React.Component {
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY(),
scale: new Animated.Value(1)
};
}
_handleStartShouldSetPanResponder(e, gestureState) {
return true;
}
_handleMoveShouldSetPanResponder(e, gestureState) {
return true;
}
componentWillMount() {
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder:
this._handleStartShouldSetPanResponder.bind(this),
onMoveShouldSetPanResponder:
this._handleMoveShouldSetPanResponder.bind(this),
onPanResponderGrant: (e, gestureState) => {
// Set the initial value to the current state
this.state.pan.setOffset({x: this.state.pan.x._value, y: this.state.pan.y._value});
this.state.pan.setValue({x: 30*Math.random(), y: 0});
Animated.spring(
this.state.scale,
{ toValue: 1.1, friction: 1 }
).start();
},
// When we drag/pan the object, set the delate to the states pan position
onPanResponderMove: Animated.event([
null, {dx: this.state.pan.x, dy: this.state.pan.y},
]),
onPanResponderRelease: (e, {vx, vy}) => {
// Flatten the offset to avoid erratic behavior
this.state.pan.flattenOffset();
Animated.spring(
this.state.scale,
{ toValue: 1, friction: 1 }
).start();
}
});
}
render() {
// Destructure the value of pan from the state
let { pan, scale } = this.state;
// Calculate the x and y transform from the pan value
let [translateX, translateY] = [pan.x, pan.y];
let rotate = '0deg';
// Calculate the transform property and set it as a value for our style which we add below to the Animated.View component
let imageStyle = {transform: [{translateX}, {translateY}, {rotate}, {scale}]};
return (
tgyyHH
);
}
}
const styles = StyleSheet.create({
container: {
width:50,
height:50,
position: 'absolute'
},
rect: {
borderRadius:4,
borderWidth: 1,
borderColor: '#fff',
width:50,
height:50,
backgroundColor:'#68a0cf',
},
txt: {
color:'#fff',
textAlign:'center'
}
});
Here is how made items independent of each other. This example is in typescript, but should be clear enough to convert to pure javascript. The main idea here is that each animated item needs its own PanResponderInstance and once you update the items, you need to also refresh the PanResponderInstance
interface State {
model: Array,
pans: Array,
dropZone1: LayoutRectangle,
dropZone2: LayoutRectangle,
}
public render(): JSX.Element {
const myAnimatedItems = new Array()
for (let i = 0; i < this.state.model.length; i++) {
const item = this.state.model[i]
const inst = this.createResponder(this.state.pans[i], item)
myAnimatedItems.push(
{item.description}
)
}
return (
{myAnimatedItems}
...
)
}
private setDropZone1 = (event: LayoutChangeEvent): void => {
this.setState({
dropZone1: event.nativeEvent.layout
})
}
private setDropZone2 = (event: LayoutChangeEvent): void => {
this.setState({
dropZone2: event.nativeEvent.layout
})
}
private isDropZone(gesture: PanResponderGestureState, dropZone: LayoutRectangle): boolean {
const toolBarHeight = variables.toolbarHeight + 15 // padding
return gesture.moveY > dropZone.y + toolBarHeight
&& gesture.moveY < dropZone.y + dropZone.height + toolBarHeight
&& gesture.moveX > dropZone.x
&& gesture.moveX < dropZone.x + dropZone.width
}
private createResponder(pan: Animated.ValueXY, item: MyAnimatedItem): PanResponderInstance {
return PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: Animated.event([null, {
dx: pan.x,
dy: pan.y
}]),
onPanResponderRelease: (_e, gesture: PanResponderGestureState) => {
const model = this.state.model
const pans = this.state.pans
const idx = model.findIndex(x => x.id === item.id)
if (this.isDropZone(gesture, this.state.dropZone1)) {
... // do something with the item if needed
// reset each PanResponderInstance
for (let i = 0; i < model.length; i++) {
pans[i] = new Animated.ValueXY()
}
this.setState({ model: model, pans: pans })
return
}
} else if (this.isDropZone(gesture, this.state.dropZone2)) {
... // do something with the item if needed
// reset each PanResponderInstance
for (let i = 0; i < model.length; i++) {
pans[i] = new Animated.ValueXY()
}
this.setState({ model: model, pans: pans })
return
}
Animated.spring(pan, { toValue: { x: 0, y: 0 } }).start()
this.setState({ scrollEnabled: true })
}
})
}
Comments
Post a Comment