import React from 'react' import { View, TouchableOpacity, StyleSheet, Animated, StyleProp, ViewStyle } from 'react-native' import { Modal, ModalProps } from '../Modal' import { SlideAnimated } from '../../common/animations' import variables from '../../common/styles/variables' export const slideModalStyles = StyleSheet.create({ container: { position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, flexDirection: 'row', alignItems: 'flex-start', justifyContent: 'center', overflow: 'hidden', }, backdrop: { position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, backgroundColor: variables.mtdFillBackdrop }, content: { position: 'absolute', overflow: 'hidden' } }) export interface SlideModalProps extends ModalProps { styles?: { root?: StyleProp, container?: StyleProp, backdrop?: StyleProp, content?: StyleProp } screenWidth?: number screenHeight?: number offsetX?: number | null | undefined offsetY?: number | null | undefined direction?: 'up' | ['up'] | ['up', 'left'] | ['up', 'right'] | 'down' | ['down'] | ['down', 'left'] | ['down', 'right'] | 'left' | ['left'] | 'right' | ['right'] align?: 'left' | 'right' | 'up' | 'down' fullScreenPatch?: boolean[] } export class SlideModal< T extends SlideModalProps, > extends Modal { static defaultProps = { ...Modal.defaultProps, styles: {}, cancelable: false, offsetX: 0, offsetY: undefined, direction: 'up', align: 'right', fullScreenPatch: [false, false, false] } constructor(props) { super(props) } // 重写 Modal 父类 init 方法 init(props, syncTag?: boolean) { const directions = [ ['up'], ['up', 'left'], ['up', 'right'], ['down'], ['down', 'left'], ['down', 'right'], ['left'], ['right'] ] const direction = typeof (props.direction) === 'string' ? [props.direction] : props.direction const propsDirectionValid = directions.some((directionItem) => { const str1 = (directionItem as any).join() const str2 = (directionItem as any).reverse().join() const str3 = direction.join() if (str3 === str1 || str3 === str2) { return true } }) if (!propsDirectionValid) { throw new TypeError(`direction 参数 ${props.direction} 为无效值`) } const directionType = [] if (direction.indexOf('up') !== -1 || direction.indexOf('down') !== -1) { directionType.push('vertical') } if (direction.indexOf('left') !== -1 || direction.indexOf('right') !== -1) { directionType.push('horizontal') } let align: any if (direction.length === 1) { if (directionType.indexOf('vertical') !== -1) { align = props.align === 'left' || props.align === 'right' ? props.align : 'right' } else { align = props.align === 'up' || props.align === 'down' ? props.align : 'down' } } let directionWithAlign = [] if (direction.length === 2) { directionWithAlign = direction } else { directionWithAlign = [ ...direction, align ] } const offsetY = typeof props.offsetY === 'number' ? props.offsetY : props.screenHeight const data = { directionType, direction, align, directionWithAlign, offsetY } this.animated = new SlideAnimated({ // duration: 1000 directionType: data.directionType, }) if (syncTag) { this.state = { ...this.state, ...data, } } else { this.setState({ ...this.state, ...data }) } } componentDidUpdate(prevProps) { if ( prevProps.direction !== this.props.direction || prevProps.align !== this.props.align || prevProps.offsetX !== this.props.offsetX || prevProps.offsetY !== this.props.offsetY || prevProps.screenWidth !== this.props.screenWidth || prevProps.screenHeight !== this.props.screenHeight ) { this.init(this.props, false) } } open(c) { return Modal.prototype.open.call(this, c) } getRects() { const { offsetX, screenWidth, screenHeight } = this.props const { directionWithAlign, offsetY } = this.state const defaultRect = { top: null, bottom: null, left: null, right: null } const contentContainerRect = { ...defaultRect } const contentRect = { ...defaultRect } const contentClockwise2Rect = { backgroundColor: 'red', ...defaultRect } const contentClockwise1Rect = { backgroundColor: 'blue', ...defaultRect } const contentClockwise3Rect = { backgroundColor: 'green', ...defaultRect } if (directionWithAlign.indexOf('up') !== -1) { contentContainerRect.top = 0 contentContainerRect.bottom = screenHeight - offsetY contentClockwise2Rect.top = offsetY contentClockwise2Rect.bottom = 0 contentClockwise1Rect.left = offsetX contentClockwise1Rect.right = 0 contentClockwise3Rect.left = 0 contentClockwise3Rect.right = screenWidth - offsetX contentRect.bottom = 0 } if (directionWithAlign.indexOf('down') !== -1) { contentContainerRect.top = offsetY contentContainerRect.bottom = 0 contentClockwise2Rect.top = 0 contentClockwise2Rect.bottom = screenHeight - offsetY contentClockwise1Rect.left = 0 contentClockwise1Rect.right = screenWidth - offsetX contentClockwise3Rect.left = offsetX contentClockwise3Rect.right = 0 contentRect.top = 0 } if (directionWithAlign.indexOf('right') !== -1) { contentContainerRect.left = offsetX contentContainerRect.right = 0 contentClockwise2Rect.left = 0 contentClockwise2Rect.right = screenWidth - offsetX contentClockwise1Rect.top = offsetY contentClockwise1Rect.bottom = 0 contentClockwise3Rect.top = 0 contentClockwise3Rect.bottom = screenHeight - offsetY contentRect.left = 0 } if (directionWithAlign.indexOf('left') !== -1) { contentContainerRect.left = 0 contentContainerRect.right = screenWidth - offsetX contentClockwise2Rect.left = offsetX contentClockwise2Rect.right = 0 contentClockwise1Rect.top = 0 contentClockwise1Rect.bottom = screenHeight - offsetY contentClockwise3Rect.top = offsetY contentClockwise3Rect.bottom = 0 contentRect.right = 0 } return { contentContainerRect, contentRect, contentClockwise1Rect, contentClockwise2Rect, contentClockwise3Rect } } getFullScreenPatch() { const { cancelable, backdropColor, fullScreenPatch } = this.props if (fullScreenPatch.length !== 3) { throw new TypeError(`fullScreenPatch 参数 ${fullScreenPatch} 为无效值`) } const rects = this.getRects() const tmp = fullScreenPatch.map((patchItem, patchIndex) => { if (patchItem) { return `contentClockwise${patchIndex + 1}Rect` } else { return '' } }).filter((tmpItem) => { return tmpItem }).map((key) => { return { key, cancelable, closeFn: this.close.bind(this, 'backdrop'), rect: { ...rects[key], backgroundColor: backdropColor, } } }) return tmp } getContent(inner?): any { const { screenWidth, screenHeight } = this.props const tmp = inner == null ? this.props.children : inner const { contentContainerRect, contentRect } = this.getRects() const fullScreenPatch = this.getFullScreenPatch() return ( { fullScreenPatch.map((patchItem, patchIndex) => { return ( { if (patchItem.cancelable) { patchItem.closeFn() } }}> ) }) } { this.handlePressBackdrop() }} /> {tmp || null} ) } handleLayout = (e: any) => { const { directionType, direction } = this.state const { width, height } = e.nativeEvent.layout const ret = [] directionType.forEach((directionTypeItem: any) => { if (directionTypeItem === 'vertical') { ret.push({ size: direction.indexOf('up') !== -1 ? height : -height, directionTypeItem, }) } if (directionTypeItem === 'horizontal') { ret.push({ size: direction.indexOf('right') !== -1 ? -width : width, directionTypeItem }) } }) this.animated.reset(ret) } }