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

本文主要是介绍React Native 的图片点击放大效果的组件使用 react-native-zoom-image,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

这篇关于React Native 的图片点击放大效果的组件使用 react-native-zoom-image的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/509786

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没