UNPKG

react-native-imagebox

Version:

huhuge

457 lines (397 loc) 12.4 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Animated, Dimensions, Modal, PanResponder, Platform, StatusBar, StyleSheet, Text, TouchableOpacity, View,Image,InteractionManager ,CameraRoll} from 'react-native'; const WINDOW_HEIGHT = Dimensions.get('window').height; const WINDOW_WIDTH = Dimensions.get('window').width; const DRAG_DISMISS_THRESHOLD = 150; const STATUS_BAR_OFFSET = (Platform.OS === 'android' ? -25 : 0); const isIOS = Platform.OS === 'ios'; // const RNFS = require('react-native-fs'); // const storeLocation = `${RNFS.DocumentDirectoryPath}`; import Swiper from 'react-native-swiper'; import ImageZoom from 'react-native-image-pan-zoom'; let BUTTONS = ["分享到朋友圈", "分享给好友", "保存相册到本地", "取消"]; let DESTRUCTIVE_INDEX = 4; let CANCEL_INDEX = 3; let _this = null const renderPagination = (index, total, context) => { return ( <View style={{ position: 'absolute', justifyContent: 'center', alignItems: 'center', top: 25, left: 0, right: 0 }}> <View style={{ borderRadius: 7, backgroundColor: 'rgba(255,255,255,.15)', padding: 3, paddingHorizontal: 7 }}> <Text style={{ color: '#fff', fontSize: 14 }}>{index + 1} / {total}</Text> </View> </View> ) }; let modelTimer = null const styles = StyleSheet.create({ background: { position: 'absolute', top: 0, left: 0, width: WINDOW_WIDTH, height: WINDOW_HEIGHT }, open: { position: 'absolute', flex: 1, justifyContent: 'center', // Android pan handlers crash without this declaration: backgroundColor: 'transparent', }, header: { position: 'absolute', top: 0, left: 0, width: WINDOW_WIDTH, backgroundColor: 'transparent', }, closeButton: { fontSize: 35, color: 'white', lineHeight: 40, width: 40, textAlign: 'center', shadowOffset: { width: 0, height: 0, }, shadowRadius: 1.5, shadowColor: 'black', shadowOpacity: 0.8 }, footDownload:{ height:60, width:Dimensions.get('window').width, backgroundColor:"#9C9C9C", position:'absolute',bottom:0, justifyContent:'center', alignItems:'center' }, wrapper: { // backgroundColor: '#000', backgroundColor: 'black', top: 0, right: 0, bottom: 0, left: 0 }, }); let fristPress = true var timers = null let imageHeight = 0 let imageWidth = 0 export default class OverlayImagebox extends Component { static propTypes = { origin: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number, width: PropTypes.number, height: PropTypes.number, }), springConfig: PropTypes.shape({ tension: PropTypes.number, friction: PropTypes.number, }), backgroundColor: PropTypes.string, isOpen: PropTypes.bool, renderHeader: PropTypes.func, onOpen: PropTypes.func, onClose: PropTypes.func, swipeToDismiss: PropTypes.bool, imagesource : PropTypes.string, imageWidth : PropTypes.number, imageHeight : PropTypes.number, timelineShare : PropTypes.func, sessionShare : PropTypes.func, }; static defaultProps = { springConfig: { tension: 30, friction: 7 }, backgroundColor: 'black', }; state = { isAnimating: false, isPanning: false, target: { x: 0, y: 0, opacity: 1, }, pan: new Animated.Value(0), openVal: new Animated.Value(0), imageWidth: this.props.imageWidth, imageHeight: this.props.imageHeight, imagesource: this.props.imagesource, width:Dimensions.get('window').width, height:Dimensions.get('window').height, bounceValue: new Animated.Value(0), showIamge : this.props.imagesource, footView: new Animated.Value(0), _this : this, showOne : true, images : this.props.images, showIndex : 0 }; constructor(props){ super(props) this.lastPositionX = null this.lastPositionY = null this.zoomCurrentDistance = null this.zoomLastDistance = null this.lastTouchStartTime = new Date().getTime() this.scale = 1 this.zoomLastDistance = 0 this.springValue = new Animated.Value(1) imageHeight = this.props.imageHeight imageWidth = this.props.imageWidth imagesource = this.props.imagesource } componentWillMount() { this.state.bounceValue.setValue(4); // 设置一个较大的初始值 Animated.spring( // 可选的基本动画类型: spring, decay, this.state.bounceValue, // 将`bounceValue`值动画化 { toValue: 1, // 将其值以动画的形式改到一个较小值 // friction: 0 // Bouncier spring } ).start(); this._panResponder = PanResponder.create({ // Ask to be the responder: onStartShouldSetPanResponder: (evt, gestureState) => !this.state.isAnimating, onStartShouldSetPanResponderCapture: (evt, gestureState) => !this.state.isAnimating, onMoveShouldSetPanResponder: (evt, gestureState) => !this.state.isAnimating, onMoveShouldSetPanResponderCapture: (evt, gestureState) => !this.state.isAnimating, onStartShouldSetResponder :(evt)=>true, // onResponderMove : (evt) => this.onResponderMove(evt), onPanResponderMove : (evt,gestureState) => this.onResponderMove(evt,gestureState), onPanResponderGrant: (evt, gestureState) => { this.state.pan.setValue(0); this.setState({ isPanning: true }); }, onPanResponderMove: Animated.event([ null, { dy: this.state.pan } ]), // 有其他组件请求接替响应者,当前的View是否“放权”?返回true的话则释放响应者权力。 onPanResponderTerminationRequest: (evt, gestureState) => true, // 手指抬起离开屏幕 onPanResponderRelease: (evt, gestureState) => { if(Math.abs(gestureState.dy) > DRAG_DISMISS_THRESHOLD) { this.setState({ isPanning: false, target: { y: gestureState.dy, x: gestureState.dx, opacity: 1 - Math.abs(gestureState.dy / WINDOW_HEIGHT) } }); this.close(); } else { Animated.spring( this.state.pan, { toValue: 0, ...this.props.springConfig } ).start(() => { this.setState({ isPanning: false }); }); } } }); } componentDidMount() { if(this.props.isOpen) { this.open(); } } open = () => { if(isIOS) { StatusBar.setHidden(true, 'fade'); } this.state.pan.setValue(0); this.setState({ isAnimating: true, showOne : false, target: { x: 0, y: 0, opacity: 1, } }); Animated.spring( this.state.openVal, { toValue: 1, ...this.props.springConfig } ).start(() => this.setState({ isAnimating: false })) } close = () => { if(isIOS) { StatusBar.setHidden(false, 'fade'); } this.setState({ isAnimating: true, showOne : true, }); Animated.spring( this.state.openVal, { toValue: 0, ...this.props.springConfig } ).start(() => { this.setState({ isAnimating: false, showOne : false }); this.props.onClose(); }); } componentWillReceiveProps(props) { if(this.props.isOpen != props.isOpen && props.isOpen) { this.open(); } } onResponderMove(evt,gestureState){ if (evt.nativeEvent.changedTouches.length <= 1) { console.log("1个手指点击") } else { console.log("两个手指点击") } } showBottom(){ this.ActionSheet.show() } swiperImage(){ const {images,imagesource} = this.state let imageArray = [] if(images&&images.length>0){ images.forEach((element,index) => { imageArray.push( <ImageZoom key = {index} cropWidth={Dimensions.get('window').width} cropHeight={Dimensions.get('window').height} imageWidth={Dimensions.get('window').width} imageHeight={Dimensions.get('window').height}> <TouchableOpacity onPress={this.close}> <Image style={{width:Dimensions.get('window').width,height:Dimensions.get('window').height}} source={{uri:element}} resizeMode="contain"/> </TouchableOpacity> </ImageZoom> ) }); } return imageArray } onScrollBeginDrag(e,state,context){ } closeModel(){ if(modelTimer){ this.timer && clearTimeout(this.timer) modelTimer = null }else{ modelTimer = "closetemp" this.timer = setTimeout(() => { this.close() modelTimer = null },1000) } } componentWillUnmount () { this.timer && clearTimeout(this.timer) } showImage(){ const {images,imagesource,showOne} = this.state this.state.showIndex = this.props.showIndex if(showOne){ return <Animated.Image style={{flex: 1,transform: [{scale: this.state.bounceValue}]}} source={{uri:imagesource}} resizeMode="contain"/> }else{ return ( <View style={{width:Dimensions.get('window').width,height:Dimensions.get('window').height}} > <Swiper style = {styles.wrapper} showsButtons={false} autoplay = {false} index = {this.props.showIndex} onScrollBeginDrag = {(e,state,context)=>{this.onScrollBeginDrag(e,state,context)}} renderPagination={renderPagination}> {this.swiperImage()} </Swiper> </View> ) } } render() { const { isOpen, renderHeader, swipeToDismiss, origin, backgroundColor } = this.props; const { isPanning, isAnimating, openVal, target, imageHeight, imageWidth, imagesource } = this.state; const lightboxOpacityStyle = { opacity: openVal.interpolate({inputRange: [0, 1], outputRange: [0, target.opacity]}) }; let handlers; if(swipeToDismiss) { handlers = this._panResponder.panHandlers; } let dragStyle; if(isPanning) { dragStyle = { top: this.state.pan, }; lightboxOpacityStyle.opacity = this.state.pan.interpolate({inputRange: [-WINDOW_HEIGHT, 0, WINDOW_HEIGHT], outputRange: [0, 1, 0]}); } const openStyle = [styles.open, { //动画篡改 插入数据 left: openVal.interpolate({inputRange: [0, 1], outputRange: [origin.x, target.x]}), top: openVal.interpolate({inputRange: [0, 1], outputRange: [origin.y + STATUS_BAR_OFFSET, target.y + STATUS_BAR_OFFSET]}), width: openVal.interpolate({inputRange: [0, 1], outputRange: [origin.width, WINDOW_WIDTH]}), height: openVal.interpolate({inputRange: [0, 1], outputRange: [origin.height, WINDOW_HEIGHT]}), }]; const background = (<Animated.View style={[styles.background, { backgroundColor: backgroundColor }, lightboxOpacityStyle]}></Animated.View>); const header = (<Animated.View style={[styles.header, lightboxOpacityStyle]}>{(renderHeader ? renderHeader(this.close) : ( <View style={{flexDirection:'row',justifyContent:"space-between" }} > <Text style={styles.closeButton} onPress={this.close} >×</Text> <Text style={[styles.closeButton,{marginRight:10}]}>...</Text> </View> ) )}</Animated.View>); const shareView = ( <View style={{height:WINDOW_HEIGHT,width:WINDOW_WIDTH,backgroundColor:'red'}}> </View> ) //{...handlers} const content = ( <Animated.View style={[openStyle, dragStyle]}> {this.showImage()} </Animated.View> ); if (this.props.navigator) { return ( <View> {background} {content} </View> ); } return ( <Modal visible={isOpen} transparent={true} onRequestClose={() => this.close()}> {background} {content} </Modal> ); } }