/
index.js
122 lines (102 loc) · 2.81 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// @flow
import React, { Component, PropTypes } from 'react'
import {
Dimensions,
Animated
} from 'react-native'
const deviceWidth = Dimensions.get('window').width
const deviceHeight = Dimensions.get('window').height
const BASE_CONTAINER_HEIGHT = 48
const orderAsc = (a, b) => a - b
export default class extends Component {
props: {
heights: number[],
onChange: (height: number) => void,
threshold: number,
tension: number,
friction: number,
children: Component<*, *, *>
}
prevHeight: number
heights: number[]
oldY: number
static defaultProps = {
threshold: 64,
tension: 50,
friction: 10,
heights: [
BASE_CONTAINER_HEIGHT,
deviceHeight
],
onChange () { return }
}
static propTypes = {
threshold: PropTypes.number,
tension: PropTypes.number,
friction: PropTypes.number,
onChange: PropTypes.func
}
state = {
containerHeight: new Animated.Value(this.props.heights[0])
}
constructor (props) {
super(props)
const { heights } = props
this.oldY = 0
this.prevHeight = heights[0]
this.heights = heights.sort(orderAsc)
this.state.containerHeight.setValue(this.prevHeight)
}
componentWillReceiveProps ({ heights }) {
if (this.props.heights.toString() !== heights.toString()) {
this.animate(this.heights[0])
}
}
handleTouchStart = ({ nativeEvent }) => {
this.oldY = nativeEvent.pageY
}
handleTouchMove = ({ nativeEvent }) => {
let newHeight = this.prevHeight + (this.oldY - nativeEvent.pageY)
const minHeight = this.heights[0]
const maxHeight = this.heights.slice(-1)[0]
if (newHeight > minHeight && newHeight < maxHeight) {
this.state.containerHeight.setValue(newHeight)
}
}
animate = (height: number, callback: Function) => {
Animated.spring(this.state.containerHeight, {
toValue: height,
tension: this.props.tension,
friction: this.props.friction
}).start(callback)
this.props.onChange(height)
this.prevHeight = height
}
handleTouchEnd = () => {
const { heights, prevHeight, animate } = this
const currentHeight = this.state.containerHeight._value
const prevIndex = heights.indexOf(prevHeight)
if (currentHeight - prevHeight >= this.props.threshold) {
return animate(heights[prevIndex + 1])
}
if (prevHeight - currentHeight >= this.props.threshold) {
return animate(heights[prevIndex - 1])
}
return animate(prevHeight)
}
render () {
return <Animated.View
style={{
position: 'absolute',
bottom: 0,
height: this.state.containerHeight,
width: deviceWidth
}}
onTouchStart={this.handleTouchStart}
onTouchMove={this.handleTouchMove}
onTouchEnd={this.handleTouchEnd}
>
{this.props.children}
</Animated.View>
}
}