Skip to content

Instantly share code, notes, and snippets.

@gaishimo
Last active January 10, 2018 23:56
Show Gist options
  • Save gaishimo/931c48e00bfe62e1408e380ed9ce8f11 to your computer and use it in GitHub Desktop.
Save gaishimo/931c48e00bfe62e1408e380ed9ce8f11 to your computer and use it in GitHub Desktop.
// @flow
import React, { Component } from 'react';
import {
StyleSheet,
View,
PanResponder,
} from 'react-native';
type State = {
dragging: boolean,
x: number,
y: number,
draggingX: number,
draggingY: number,
}
type GestureState = {
dx: number,
dy: number,
}
export default class App extends Component<{}, State> {
state: State = {
dragging: false,
x: 100,
y: 100,
draggingX: 100,
draggingY: 100,
}
panResponder: any
componentWillMount() {
this.createPanResponder()
}
createPanResponder() {
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: this.onStartShouldSetPanResponder,
onStartShouldSetPanResponderCapture: this.onStartShouldSetPanResponderCapture,
onMoveShouldSetPanResponder: this.onMoveShouldSetPanResponder,
onMoveShouldSetPanResponderCapture: this.onMoveShouldSetPanResponderCapture,
onPanResponderGrant: this.onPanResponderGrant,
onPanResponderMove: this.onPanResponderMove,
onPanResponderTerminationRequest: this.onPanResponderTerminationRequest,
onPanResponderRelease: this.onPanResponderEnd,
onPanResponderTerminate: this.onPanResponderEnd,
onShouldBlockNativeResponder: (evt, gestureState) => {
return true;
},
})
}
onStartShouldSetPanResponder (e: Object, gestureState: GestureState) {
return true
}
onMoveShouldSetPanResponder (e: Object, gestureState: GestureState) {
return true
}
onMoveShouldSetPanResponderCapture (e: Object, gestureState: GestureState) {
return true
}
onPanResponderGrant = (e: Object, gestureState: GestureState) => {
this.setState({ dragging: true })
}
onStartShouldSetPanResponderCapture = (e: Object, gestureState: GestureState) => {
return true
}
onPanResponderMove = (e: Object, gestureState: GestureState) => {
const { x, y } = this.state
const { dx, dy } = gestureState
this.setState({
draggingX: x + dx,
draggingY: y + dy,
})
}
onPanResponderEnd = (e: Object, gestureState: GestureState) => {
this.setState({
x: this.state.draggingX,
y: this.state.draggingY,
dragging: false,
})
}
onPanResponderTerminationRequest(e: Object, gestureState: GestureState) {
return true
}
render() {
const { x, y, dragging, draggingX, draggingY } = this.state
const backgroundColor = dragging ? '#FFEF15' : 'rgb(200, 240, 250)'
const left = dragging ? draggingX : x
const top = dragging ? draggingY : y
return (
<View
style={[
styles.responder,
{
backgroundColor,
left,
top,
}
]}
{...this.panResponder.panHandlers}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
responder: {
position: 'absolute',
width: 100,
height: 100,
borderRadius: 10,
},
});
// @flow
import React, { Component } from 'react';
import {
StyleSheet,
View,
PanResponder,
Text,
} from 'react-native';
type State = {
dragging: boolean,
radius: number,
moveX: ?number,
moveY: ?number,
}
type GestureState = Object
const centerX = 180
const centerY = 300
const minRadius = 30
const maxRadius = 120
export default class App extends Component<{}, State> {
state: State = {
dragging: false,
radius: 30,
moveX: null,
moveY: null,
}
panResponder: any
componentWillMount() {
this.createPanResponder()
}
createPanResponder() {
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: this.onStartShouldSetPanResponder,
onStartShouldSetPanResponderCapture: this.onStartShouldSetPanResponderCapture,
onMoveShouldSetPanResponder: this.onMoveShouldSetPanResponder,
onMoveShouldSetPanResponderCapture: this.onMoveShouldSetPanResponderCapture,
onPanResponderGrant: this.onPanResponderGrant,
onPanResponderMove: this.onPanResponderMove,
onPanResponderTerminationRequest: this.onPanResponderTerminationRequest,
onPanResponderRelease: this.onPanResponderEnd,
onPanResponderTerminate: this.onPanResponderEnd,
onShouldBlockNativeResponder: this.onShouldBlockNativeResponder,
})
}
onStartShouldSetPanResponder (e: Object, gestureState: GestureState) {
return true
}
onMoveShouldSetPanResponder (e: Object, gestureState: GestureState) {
return true
}
onMoveShouldSetPanResponderCapture (e: Object, gestureState: GestureState) {
return true
}
onPanResponderGrant = (e: Object, gestureState: GestureState) => {
this.setState({ dragging: true })
}
onStartShouldSetPanResponderCapture = (e: Object, gestureState: GestureState) => {
return true
}
onPanResponderMove = (e: Object, gestureState: GestureState) => {
const { moveX, moveY, x0, y0, dx, dy, vx, vy } = gestureState
const previousMoveX = this.state.moveX
const previousMoveY = this.state.moveY
if (previousMoveX == null || previousMoveY == null) {
this.setState({ moveX, moveY })
return
}
const xFromCenter = Math.abs(centerX - moveX)
const yFromCenter = Math.abs(centerY - moveY)
const previousXFromCenter = Math.abs(centerX - previousMoveX)
const previousYFromCenter = Math.abs(centerY - previousMoveY)
const useHorizontalChange = Math.abs(xFromCenter) > Math.abs(yFromCenter)
const expanding = useHorizontalChange ?
xFromCenter > previousXFromCenter
: yFromCenter > previousYFromCenter
let radius = useHorizontalChange ? xFromCenter : yFromCenter
radius = Math.round(radius / 10) * 10
if (expanding) {
if (this.state.radius > radius || radius > maxRadius) {
// 大きくしようとしているが元より小さい場合
this.setState({ moveX, moveY })
return
}
} else {
if (this.state.radius < radius || radius < minRadius) {
// 小さくしようとしているが元より大きい場合
this.setState({ moveX, moveY })
return
}
}
this.setState({ radius })
}
onPanResponderEnd = (e: Object, gestureState: GestureState) => {
this.setState({
dragging: false,
moveX: null,
moveY: null,
})
}
onPanResponderTerminationRequest(e: Object, gestureState: GestureState) {
return true
}
onShouldBlockNativeResponder(e: Object, gestureState: GestureState) {
return true
}
render() {
const { dragging, radius } = this.state
const backgroundColor = dragging ? '#CCE8E8' : '#B0D3E1'
const width = radius * 2
const height = radius * 2
const left = centerX - radius
const top = centerY - radius
const num = radius / 10 - 2
// console.log(left, top, width, height)
return (
<View
style={[
styles.responder,
{
left,
top,
width,
height,
backgroundColor,
borderRadius: radius,
}
]}
{...this.panResponder.panHandlers}
>
<Text style={styles.num}>{num}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
responder: {
position: 'absolute',
justifyContent: 'center',
alignItems: 'center',
},
num: {
color: 'white',
fontSize: 28,
fontWeight: 'bold',
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment