react-native-swipeable-up-down
Version:
145 lines (132 loc) • 3.87 kB
JavaScript
import React, { Component } from 'react'
import {
View,
Animated,
TouchableWithoutFeedback,
StatusBar,
Dimensions
} from 'react-native'
import Interactable from 'react-native-interactable'
import styles from './styles'
// README: When you're using this components with new content,
// you should create new component with View absolute and pointerEvents='box-none'
const DEVICE_HEIGHT = Dimensions.get('screen').height
const DEFAULT_MAX_HEIGHT = 5 + (StatusBar.currentHeight || 0)
type Props = {
snapPoints: Array,
onStateChange: Function,
initialPosition: Object,
boundaries: Object,
isList: Boolean,
childrenRef: Function, // If you're using list in SwipeableBox, you need pass your Reference of List,
extraHeight: Number // Should extra height is Navigation bar height (Header.HEIGHT - Header from react-naviagtion)
}
type State = {
scrollEnabled: Boolean,
boxVisible: Boolean
}
export default class SwipeableBox extends Component<Props, State> {
static defaultProps = {
snapPoints: [
{ y: DEFAULT_MAX_HEIGHT },
{ y: DEVICE_HEIGHT * 0.4 },
{ y: DEVICE_HEIGHT }
],
initialPosition: {
y: DEVICE_HEIGHT
},
boundaries: {
top: DEFAULT_MAX_HEIGHT,
bottom: DEVICE_HEIGHT
},
isList: false,
extraHeight: 0
}
constructor(props) {
super(props)
this.state = {
scrollEnabled: false,
boxVisible: false,
snapPoints: props.snapPoints,
initialPosition: props.initialPosition,
boundaries: props.boundaries
}
this._deltaY = new Animated.Value(0)
this.MAX_HEIGHT = DEFAULT_MAX_HEIGHT + props.extraHeight
}
render() {
const { boxVisible, snapPoints, initialPosition, boundaries } = this.state
return (
<View style={styles.panelContainer} pointerEvents='box-none'>
{boxVisible && (
<TouchableWithoutFeedback onPress={this.hide}>
<Animated.View
pointerEvents={boxVisible ? 'auto' : 'box-none'}
style={[
styles.panelContainer,
{
backgroundColor: 'black',
opacity: this._deltaY.interpolate({
inputRange: [0, snapPoints[snapPoints.length - 1].y],
outputRange: [0.5, 0],
extrapolateRight: 'clamp'
})
}
]}
/>
</TouchableWithoutFeedback>
)}
<Interactable.View
style={styles.panelContainer}
ref='swipeable'
verticalOnly
snapPoints={snapPoints}
boundaries={boundaries}
initialPosition={initialPosition}
onSnap={this._onSnap}
dragEnabled={true}
animatedValueY={this._deltaY}
>
<View
style={{
height: DEVICE_HEIGHT - DEFAULT_MAX_HEIGHT
}}
>
{this.props.children}
</View>
</Interactable.View>
</View>
)
}
_onSnap = ({ nativeEvent }) => {
const { isList, childrenRef } = this.props
if (isList) {
const scrollEnabled = nativeEvent.index === 0
childrenRef.setNativeProps({
scrollEnabled
})
}
const isOpened = nativeEvent.index !== this.state.snapPoints.length - 1
if (!isOpened) {
this._toggleVisible(false)
}
this.props.onStateChange && this.props.onStateChange(isOpened)
}
_toggleVisible = val => {
if (this.state.boxVisible === val) {
return
}
this.setState({ boxVisible: val })
}
show = () => {
this.refs.swipeable.snapTo({ index: 1 })
this._toggleVisible(true)
}
hide = () => {
this.refs.swipeable.snapTo({
index: this.state.snapPoints.length - 1
})
this._toggleVisible(false)
}
isVisble = () => this.state.boxVisible
}