本文主要是介绍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, ( w, h) => {
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), ( x, y, w, h, px, py) => {
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 : ( evt, gestureState) => this.props.startCapture,
onMoveShouldSetPanResponder : this._onMoveShouldSetPanResponder. bind(this),
onMoveShouldSetPanResponderCapture : ( evt, gestureState) => this.props.moveCapture,
onPanResponderTerminationRequest : ( evt, gestureState) => true,
onPanResponderGrant : this._handlePanResponderGrant. bind(this),
onPanResponderMove : this._handlePanResponderMove. bind(this),
onPanResponderRelease : this._handlePanResponderEnd. bind(this),
onPanResponderTerminate : this._handlePanResponderEnd. bind(this),
onShouldBlockNativeResponder : ( evt, gestureState) => true
});
}
_onStartShouldSetPanResponder ( evt, gestureState) {
// set responder for tapping when the drawer is open
// TODO: tap close
if (this._inAnimation) return;
return false;
}
_onMoveShouldSetPanResponder ( evt, gestureState) {
// custom pan responder condition function
if (this._inAnimation) return;
if (this.props.responderNegotiate && this.props. responderNegotiate(evt, gestureState) === false) return false;
if (this. _touchPositionCheck(gestureState)) {
return true;
}
return false;
}
_handlePanResponderGrant( evt, gestureState) {
}
_handlePanResponderMove ( evt, gestureState) {
const { dy} = gestureState;
this. _updateNativeStyles(dy);
}
_handlePanResponderEnd ( evt, gestureState) {
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 { dx, dy} = gestureState;
if ( Math. abs(dy) <= Math. abs(dx)) {
return false;
}
return true;
}
_closeModal( isDown) {
const { easingFunc, onClose} = 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 { duration, easingFunc} = 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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!