UNPKG

react-native-modal-animated

Version:

Simple and powerfull component enhances the original react-native modal by adding animations and many possible customizations while still providing nice interface

218 lines (196 loc) 4.75 kB
import React, { Component } from 'react'; import { Animated, Easing, TouchableOpacity, StyleSheet } from 'react-native'; export interface AnimatedModalProps { noAnimation?: boolean; visible: boolean; animationType?: string; modalCardPosition?: string; style?: any; duration?: number; onBackdropPress: () => void; } export interface AnimatedModalState { visible: boolean; } export default class AnimatedModal extends Component< AnimatedModalProps, AnimatedModalState > { visibility: Animated.Value; state; props; setState; constructor(props) { super(props); this.state = { visible: props.visible }; } componentWillMount() { this.visibility = new Animated.Value(this.props.visible ? 1 : 0); } componentWillReceiveProps(nextProps) { if (nextProps.visible) { this.setState({ visible: true }); } Animated.timing(this.visibility, { toValue: nextProps.visible ? 1 : 0, easing: Easing.cubic, duration: this.props.duration ? this.props.duration : 300 }).start(() => { this.setState({ visible: nextProps.visible }); }); } render() { const { visible, style, children, ...rest } = this.props; let containerStyle, positionStyle; const defaultAnimationStyle = { opacity: this.visibility.interpolate({ inputRange: [0, 1], outputRange: [0, 1] }), transform: [ { scale: this.visibility.interpolate({ inputRange: [0, 1], outputRange: [1.1, 1] }) } ] }; const varticalFlipAnimation = { opacity: this.visibility.interpolate({ inputRange: [0, 1], outputRange: [0, 1] }), transform: [ { rotateX: this.visibility.interpolate({ inputRange: [0, 1], outputRange: ['270deg', '360deg'] }) } ] }; const flipAndScaleAnimation = { opacity: this.visibility.interpolate({ inputRange: [0, 1], outputRange: [0, 1] }), transform: [ { rotateX: this.visibility.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'] }) }, { scale: this.visibility.interpolate({ inputRange: [0, 1], outputRange: [0, 1] }) } ] }; const horizontalFlipAnimation = { opacity: this.visibility.interpolate({ inputRange: [0, 1], outputRange: [0, 1] }), transform: [ { rotateY: this.visibility.interpolate({ inputRange: [0, 1], outputRange: ['270deg', '360deg'] }) } ] }; switch (this.props.animationType) { case 'vertical': containerStyle = varticalFlipAnimation; break; case 'horizontal': containerStyle = horizontalFlipAnimation; break; case 'flipAndScale': containerStyle = flipAndScaleAnimation; break; default: containerStyle = defaultAnimationStyle; break; } switch (this.props.modalCardPosition) { case 'center': positionStyle = styles.centerStyle; break; case 'bottom': positionStyle = styles.bottomStyle; break; case 'top': positionStyle = styles.topStyle; break; default: positionStyle = styles.centerStyle; break; } /** */ const combinedStyle = [ !this.props.noAnimation ? containerStyle : null, style ]; const layerStyle = { position: 'absolute', zIndex: 99, top: 0, bottom: 0, left: 0, right: 0, backgroundColor: `rgba(0,0,0,0.5)` }; return ( <TouchableOpacity activeOpacity={1} onPress={this.props.onBackdropPress} style={this.state.visible ? layerStyle : null} > <Animated.View style={[this.state.visible ? combinedStyle : containerStyle, positionStyle]} {...rest} > {this.state.visible ? children : null} </Animated.View> </TouchableOpacity> ); } } const styles = StyleSheet.create({ centerStyle: { position: 'absolute', zIndex: 100, left: 0, right: 0, top: 0, bottom: 0, justifyContent: 'center', alignItems: 'center' }, bottomStyle: { position: 'absolute', zIndex: 100, left: 0, right: 0, bottom: 50, justifyContent: 'center', alignItems: 'center' }, topStyle: { position: 'absolute', zIndex: 100, left: 0, right: 0, top: 50, justifyContent: 'center', alignItems: 'center' } });