UNPKG

react-native-sliding-up-down-panel-galesburg

Version:

Sliding up and sliding down panels for android and ios | react native

232 lines (217 loc) 8.01 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Platform, StyleSheet, Text, View, Animated, Dimensions, PanResponder, TouchableOpacity, } from 'react-native'; const { width, height } = Dimensions.get('window'); let sliderPosition = 0; const styles = StyleSheet.create({ headerPanelViewStyle: { width, backgroundColor: '#ff0032', position: 'absolute', alignSelf: 'flex-end', justifyContent: 'center', alignItems: 'center', flex: 1 }, }); const HeaderView = (props) => ( <View style={{backgroundColor: 'green',}}><Text style={{color: 'white'}}>Hello world</Text></View> ) const SlidingPanelView = (props) => ( <View style={{height: 200, width, backgroundColor: 'blue'}}><Text style={{color: 'white'}}>Hello world</Text></View> ) const SlidingPanelIOS = (props) => ( <Animated.View style={props.panelPosition === 'bottom' ? {bottom: props.heightAnim, flex: 1, position: 'absolute',} : {top: props.heightAnim, flex: 1, position: 'absolute',}}> <Animated.View {...props.panResponder} style={{height: props.headerPanelHeight,}}> {props.headerView()} </Animated.View> <View style={props.panelPosition === 'bottom' ? {top: props.headerPanelHeight, left: 0, position: 'absolute',} : {bottom: props.headerPanelHeight, left: 0, position: 'absolute',}}> {props.slidingPanelView()} </View> </Animated.View> ); const SlidingPanelAndroid = (props) => ( <Animated.View style={props.panelPosition === 'bottom' ? {bottom: props.heightAnim, flex: 1, position: 'absolute',} : {top: props.heightAnim, flex: 1, position: 'absolute',}}> <Animated.View {...props.panResponder} style={{height: props.headerPanelHeight,}}> {props.headerView()} </Animated.View> <Animated.View style={props.panelPosition === 'bottom' ? {top: props.headerPanelHeight, left: 0, position: 'absolute',} : {bottom: props.headerPanelHeight, left: 0, position: 'absolute',}}> {props.slidingPanelView()} </Animated.View> </Animated.View> ); export default class SlidingPanel extends Component { constructor(props) { super(props); this.state = { heightAnim: new Animated.Value(0), panResponder: {}, }; } componentWillMount() { var a = 0; this.state.panResponder = PanResponder.create({ onStartShouldSetPanResponder : () => true, onPanResponderGrant: (evt, gestureState) => { a = 0; }, onPanResponderMove: (event, gestureState) => { if(this.props.allowDragging) { if(a === 0) { this.props.onDragStart(event, gestureState); } else { this.props.onDrag(event, gestureState); } if(this.props.panelPosition === 'bottom') { a = gestureState.dy * -1; } else { a = gestureState.dy * 1; } if((Platform.OS === 'android' ? sliderPosition + a < height - (this.props.headerLayoutHeight + 370): sliderPosition + a < height - (this.props.headerLayoutHeight -2)) && sliderPosition + a > -2){ if(sliderPosition !== 0) { this.state.heightAnim.setValue(sliderPosition + a) } else { this.state.heightAnim.setValue(a) } } } }, onPanResponderRelease : (e, gesture) => { sliderPosition = sliderPosition + a if(a !== 0) { this.props.onDragStop(e, gesture) } if(this.props.allowAnimation) { if(a === 0 || (this.props.panelPosition === 'bottom' ? gesture.vy < -1 : gesture.vy > 1)) { if(sliderPosition < height-this.props.headerLayoutHeight) { sliderPosition = height-this.props.headerLayoutHeight this.props.onAnimationStart(); Animated.timing( this.state.heightAnim, { toValue: Platform.OS === 'android' ? height-this.props.headerLayoutHeight - 370 : height-this.props.headerLayoutHeight - 350, duration: this.props.AnimationSpeed, } ).start(() => this.props.onAnimationStop()); } else { sliderPosition = 0 this.props.onAnimationStart(); Animated.timing( this.state.heightAnim, { toValue: 0, duration: this.props.AnimationSpeed, } ).start(() => this.props.onAnimationStop()); } } if(this.props.panelPosition === 'bottom' ? gesture.vy > 1 : gesture.vy < -1) { sliderPosition = 0 this.props.onAnimationStart(); Animated.timing( this.state.heightAnim, { toValue: 0, duration: this.props.AnimationSpeed, } ).start(() => this.props.onAnimationStop()); } } }, }); } onRequestClose() { sliderPosition = 0 Animated.timing( this.state.heightAnim, { toValue: 0, duration: this.props.AnimationSpeed, } ).start(); } onRequestStart() { sliderPosition = height-this.props.headerLayoutHeight Animated.timing( this.state.heightAnim, { toValue: Platform.OS === 'android' ? height-this.props.headerLayoutHeight - 25 : height-this.props.headerLayoutHeight, duration: this.props.AnimationSpeed, } ).start(); } render() { return ( <View style={this.props.panelPosition === 'bottom' ? {position: 'absolute', bottom: 270} : {position: 'absolute', top: 0}}> { Platform.OS === 'ios' && this.props.visible === true ? <SlidingPanelIOS panResponder = {this.state.panResponder.panHandlers} panelPosition={this.props.panelPosition} headerPanelHeight={this.props.headerLayoutHeight} headerView = {() => this.props.headerLayout()} heightAnim={this.state.heightAnim} visible={this.props.visible} slidingPanelView={() => this.props.slidingPanelLayout()} /> : this.props.visible === true && <SlidingPanelAndroid panResponder = {this.state.panResponder.panHandlers} panelPosition={this.props.panelPosition} headerPanelHeight={this.props.headerLayoutHeight} headerView = {() => this.props.headerLayout()} heightAnim={this.state.heightAnim} visible={this.props.visible} slidingPanelView={() => this.props.slidingPanelLayout()} /> } </View> ); } } SlidingPanel.propTypes = { headerLayoutHeight: PropTypes.number.isRequired, headerLayout: PropTypes.func.isRequired, slidingPanelLayout: PropTypes.func.isRequired, AnimationSpeed: PropTypes.number, slidingPanelLayoutHeight: PropTypes.number, panelPosition: PropTypes.string, visible: PropTypes.bool, allowDragging: PropTypes.bool, allowAnimation: PropTypes.bool, onDragStart: (event, gestureState) => {}, onDragStop: (event, gestureState) => {}, onDrag: (event, gestureState) => {}, onAnimationStart: () => {}, onAnimationStop: () => {}, }; SlidingPanel.defaultProps = { panelPosition: 'bottom', headerLayoutHeight: 50, headerLayout: () => {}, visible: true, onDragStart: (event, gestureState) => {}, onDragStop: (event, gestureState) => {}, onDrag: (event, gestureState) => {}, onAnimationStart: () => {}, onAnimationStop: () => {}, slidingPanelLayout: () => {}, allowDragging: true, allowAnimation: true, slidingPanelLayoutHeight: 0, AnimationSpeed: 400, };