React Native 的图片点击放大效果的组件使用 react-native-zoom-image

    xiaoxiao2021-04-12  41

    1.在index.android.js下书写

    /**  * Created by TinySymphony on 2017-03-23.  */ import React, {Component}  from  'react'; import {   StyleSheet,   AppRegistry,   View,   Text,   Easing,   ScrollView }  from  'react-native'; import ZoomImage  from  './ZoomImage'; export default  class  App  extends  Component {    constructor( props) {     super(props);     this.text  =  '';   }    render() {      return (        <ScrollView >          <View style ={styles.content} >            < Text style ={styles.txt} >Zoom Image Examples ! Try to click them ~</ Text >            <View style ={styles.imgItem} >              <ZoomImage               source ={{uri :  'https://avatars2.githubusercontent.com/u/7685233?v=3&s=460'}}               imgStyle ={{width :  220, height :  220}}               style ={styles.img}                />            </View >            <View style ={styles.imgItem} >              <ZoomImage               source ={{uri :  'https://ooo.0o0.ooo/2017/03/31/58de0e9b287f6.jpg'}}               imgStyle ={{width :  250, height :  230}}               style ={styles.img}               enableScaling ={ true}                />            </View >            <View style ={styles.imgItem} >              <ZoomImage               source ={{uri :  'https://ooo.0o0.ooo/2017/03/31/58de0e9b28328.jpg'}}               imgStyle ={{width :  250, height :  240}}               style ={styles.img}               easingFunc ={Easing.bounce}                />            </View >          </View >        </ScrollView >     );   } } const  styles  =  StyleSheet. create({   content : {     justifyContent :  'center',     alignItems :  'center'   },   txt : {     fontSize :  16,     marginTop :  50,     color :  '#333'   },   img : {     borderWidth :  3,     borderColor :  '#45b7d5'   },   imgItem : {     justifyContent :  'center',     alignItems :  'center',     margin :  20   } }); AppRegistry. registerComponent( 'App', ()  => App); // export default App; // import { AppRegistry } from 'react-native'; // import App from './App'; // AppRegistry.registerComponent('Example', (): App => App);

    2.ZoomImage.js文件

    import React, {PropTypes, Component}  from  'react'; import {   View,   Text,   Image,   Modal,   Easing,   StyleSheet,   PanResponder,   NativeModules,   findNodeHandle,   Dimensions,   TouchableWithoutFeedback }  from  'react-native'; import Animation  from  './Animation'; const  winWidth  = Dimensions. get( 'window').width; const  winHeight  = Dimensions. get( 'window').height; const  winRatio  = winWidth  / winHeight; const  RCTUIManager  = NativeModules.UIManager; class  ZoomImage  extends  Component {    static propTypes  = {     startCapture : PropTypes.bool,     moveCapture : PropTypes.bool,     responderNegotiate : PropTypes.func,     easingFunc : PropTypes.func,     duration : PropTypes.number,     enableScaling : PropTypes.bool   }    static defaultProps  = {     startCapture :  false,     moveCapture :  false,     duration :  800,     easingFunc : Easing.ease,     enableScaling :  false   }    constructor( props) {     super(props);     this.state  = {       maxSize : {         width :  0,         height :  0       },       isModalVisible :  false     };     this.enableModal  =  false;     this.closeModal  = this.closeModal. bind(this);     this.openModal  = this.openModal. bind(this);     this.getMaxSizeByRatio  = this.getMaxSizeByRatio. bind(this);   }    getMaxSizeByRatio ( ratio) {      return {       width : ratio  >= winRatio  ? winWidth  : winWidth  / ratio,       height : ratio  >= winRatio  ? winWidth  / ratio  : winHeight     };   }    componentDidMount () {      if (this.props.source.uri) {       Image. getSize(this.props.source.uri, ( wh=> {         this. setState(( state=> {           state.maxSize  = this. getMaxSizeByRatio(w  / h);           this.enableModal  =  true;         });       });     }  else {       this. setState(( state=> {         state.maxSize  = this. getMaxSizeByRatio(this.props.imgStyle.width  / this.props.imgStyle.height);         this.enableModal  =  true;       });     }   }    openModal () {      if ( !this.refs.view  ||  !this.enableModal)  return;     RCTUIManager. measure( findNodeHandle(this.refs.view), ( xywhpxpy=> {       this.originPosition  = {x, y, w, h, px, py};     });     this. setState({       isModalVisible :  true     });   }    closeModal () {     this. setState({       isModalVisible :  false     });   }    render () {      return (        <TouchableWithoutFeedback style ={this.props.imgStyle}         onPress ={this.openModal}         ref = "view" >          <View style ={this.props.style} >            <Image             source ={this.props.source}             resizeMode ={this.props.resizeMode}             style ={this.props.imgStyle} />            <ImageModal             visible ={this.state.isModalVisible}             onClose ={this.closeModal}             originPosition ={this.originPosition}             size ={this.state.maxSize}             minAlpha ={this.props.minAlpha}             source ={this.props.source}             duration ={this.props.duration}             easingFunc ={this.props.easingFunc}             enableScaling ={this.props.enableScaling} />          </View >        </TouchableWithoutFeedback >     );   } } class  ImageModal  extends  Component {    constructor( props) {     super(props);     this._initModalStyle  = {       style : {         backgroundColor :  'rgba(0, 0, 0, 1)'       }     };     this._modalStyle  =  JSON. parse( JSON. stringify(this._initModalStyle));     this._initContentStyle  = {       style : {         top :  0,         bottom :  0,         left :  0,         right :  0       }     };     this._contentStyle  =  JSON. parse( JSON. stringify(this._initContentStyle));     this._initImgSize  = {       style : this.props.size     };     this._imgSize  =  JSON. parse( JSON. stringify(this._initImgSize));     this._inAnimation  =  false;     this._setNativeProps  = this._setNativeProps. bind(this);     this._closeModalByTap  = this._closeModalByTap. bind(this);     this._closeModal  = this._closeModal. bind(this);     this._rebounce  = this._rebounce. bind(this);     this._touchPositionCheck  = this._touchPositionCheck. bind(this);     this._updateNativeStyles  = this._updateNativeStyles. bind(this);     this._pan  = PanResponder. create({       onStartShouldSetPanResponder : this._onStartShouldSetPanResponder. bind(this),        onStartShouldSetPanResponderCapture : ( evtgestureState=> this.props.startCapture,       onMoveShouldSetPanResponder : this._onMoveShouldSetPanResponder. bind(this),        onMoveShouldSetPanResponderCapture : ( evtgestureState=> this.props.moveCapture,        onPanResponderTerminationRequest : ( evtgestureState=>  true,       onPanResponderGrant : this._handlePanResponderGrant. bind(this),       onPanResponderMove : this._handlePanResponderMove. bind(this),       onPanResponderRelease : this._handlePanResponderEnd. bind(this),       onPanResponderTerminate : this._handlePanResponderEnd. bind(this),        onShouldBlockNativeResponder : ( evtgestureState=>  true     });   }    _onStartShouldSetPanResponder ( evtgestureState) {      // set responder for tapping when the drawer is open      // TODO: tap close      if (this._inAnimation)  return;      return  false;   }    _onMoveShouldSetPanResponder ( evtgestureState) {      // custom pan responder condition function      if (this._inAnimation)  return;      if (this.props.responderNegotiate  && this.props. responderNegotiate(evt, gestureState)  ===  falsereturn  false;      if (this. _touchPositionCheck(gestureState)) {        return  true;     }      return  false;   }    _handlePanResponderGrant( evtgestureState) {   }    _handlePanResponderMove ( evtgestureState) {      const { dy= gestureState;     this. _updateNativeStyles(dy);   }    _handlePanResponderEnd ( evtgestureState) {      const { dy= gestureState;      if (dy  >  0.4  * winHeight) {       this. _closeModal( true);     }  else  if ( -dy  >  0.4  * winHeight) {       this. _closeModal( false);     }  else {       this. _rebounce();     }   }    _touchPositionCheck( gestureState) {      const { dxdy= gestureState;      if ( Math. abs(dy)  <=  Math. abs(dx)) {        return  false;     }      return  true;   }    _closeModal( isDown) {      const { easingFunconClose= this.props;      let current  = this._contentStyle.style.top;     this._inAnimation  =  true;      new  Animation({       start : current,       end : isDown  ? winHeight  :  -winHeight,       duration :  140,       easingFunc,        onAnimationFrame : ( val=> {         this. _updateNativeStyles(val);       },        onAnimationEnd : ()  => {         this._inAnimation  =  false;          onClose();         this. _setNativeProps( true);       }     }).start();   }    _closeModalByTap() {      if (this._inAnimation) {        return  false;     }     this. _closeModal( true);   }    _rebounce( isDown) {      const { durationeasingFunc= this.props;      let current  = this._contentStyle.style.top;     this._inAnimation  =  true;      new  Animation({       start : current,       end :  0,       duration :  Math. abs(current  / winHeight)  * duration,       easingFunc,        onAnimationFrame : ( val=> {         this. _updateNativeStyles(val);       },        onAnimationEnd : ()  => {         this._inAnimation  =  false;       }     }).start();   }    _updateNativeStyles( dy) {      const {        width,        height     }  = this.props.size;      // this._contentStyle.style.left = dx;      // this._contentStyle.style.right = -dx;     this._contentStyle.style.top  = dy;     this._contentStyle.style.bottom  =  -dy;     this._modalStyle.style.backgroundColor  =  `rgba(0, 0, 0, ${ 1   -   Math . abs (dy)  /  winHeight  *   0.9 })`;      if (this.props.enableScaling) {       this._imgSize.style.width  = width  * ( 1  -  Math. abs(dy  / winHeight)  *  0.6);       this._imgSize.style.height  = height  * ( 1  -  Math. abs(dy  / winHeight)  *  0.6);     }  else {       this._imgSize.style.width  = width;       this._imgSize.style.height  = height;     }     this. _setNativeProps();   }    _setNativeProps( isReset) {      if (isReset) {       this._contentStyle  =  JSON. parse( JSON. stringify(this._initContentStyle));       this._modalStyle  =  JSON. parse( JSON. stringify(this._initModalStyle));       this._imgSize  =  JSON. parse( JSON. stringify(this._initImgSize));     }     this.content  && this.content. setNativeProps(this._contentStyle);     this.mask  && this.mask. setNativeProps(this._modalStyle);     this.img  && this.img. setNativeProps(this._imgSize);   }    componentDidUpdate () {      new  Animation({       start :  0,       end :  1,       duration :  100,       easingFunc : Easing.ease,        onAnimationFrame : ( val=> {         this.mask  && this.mask. setNativeProps({style : {           opacity : val         }});       },        onAnimationEnd : ()  => {         this._inAnimation  =  false;       }     }).start();   }    render () {      const {        visible,        onClose,        source,        size   // origin size of the image     }  = this.props;      if (visible) { this._inAnimation  =  true; }     this._initImgSize.style  = size;      return (        <Modal         visible ={visible}         transparent ={ true}         onRequestClose ={onClose} >          <View style ={styles.mask} ref ={ mask  => {this.mask  = mask;}} { ...this._pan.panHandlers} >            <TouchableWithoutFeedback             ref ={ ref  => {this.imgContainer  = ref;}}             onPress ={this._closeModalByTap} >              <View               ref ={ ref  => {this.content  = ref;}}               style ={styles.content} >                <Image ref ={ img  => {this.img  = img;}} source ={source} style ={[size, styles.img]} />              </View >            </TouchableWithoutFeedback >          </View >        </Modal >     );   } } const  styles  =  StyleSheet. create({   mask : {     position :  'absolute',     right :  0,     left :  0,     top :  0,     bottom :  0,     backgroundColor :  'rgba(0, 0, 0, 1)',     opacity :  0   },   content : {     position :  'absolute',     right :  0,     left :  0,     top :  0,     bottom :  0,     justifyContent :  'center',     alignItems :  'center',     backgroundColor :  'transparent'   },   toucharea : {     flex :  1,     justifyContent :  'center',     alignItems :  'center',     alignSelf :  'stretch'   },   modalText : {     color :  '#fff'   },   img : {   } }); ZoomImage.ImageModal  = ImageModal; export default ZoomImage;

    3.Animation.js

    export default  function  Animation( option) {   this.animate  = this.animate. bind(this);   this.start  = this.start. bind(this);   this.option  = option; } Animation.prototype. animate  =  function ( now) {    const {      start,      end,      duration,      onAnimationFrame,      onAnimationEnd  = ()  => {},      easingFunc  =  t  => t   }  = this.option;    var currentDuration  = now  - this.startTime;    if (currentDuration  >= duration) {      onAnimationFrame(end);      onAnimationEnd();      return;   }    let value;    if (start  > end) {     value  = start  - (start  - end)  *  easingFunc(currentDuration  / duration);   }  else {     value  = (end  - start)  *  easingFunc(currentDuration  / duration)  + start;   }    onAnimationFrame(value);    requestAnimationFrame(this.animate); }; Animation.prototype. start  =  function () {   this.startTime  =  new  Date();   this. animate(this.startTime); };

    Examples效果如下

    项目原地址https://github.com/Tinysymphony/react-native-zoom-image
    转载请注明原文地址: https://ju.6miu.com/read-667303.html

    最新回复(0)