微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

react-native – 具有双指缩放功能的可滚动图像

我正在尝试在我的React Native应用程序(Android)中显示图像,我想让用户能够放大和缩小图像.
这也要求图像一旦放大就可以滚动.

我该怎么办呢?

我尝试使用ScrollView在里面显示更大的图像,但在Android上它可以垂直或水平滚动,而不是两种方式.
即使这有效,也存在进行缩放工作的问题.

据我所知,我需要在自定义视图上使用PanResponder来缩放图像并相应地定位它.有更容易的方法吗?

我最终滚动了自己的ZoomableImage组件.到目前为止,它一直很好,这里是代码
import React,{Component,PropTypes} from 'react';
import { Text,View,PanResponder,Image } from 'react-native';

function calcdistance(x1,y1,x2,y2) {
    let dx = Math.abs(x1 - x2)
    let dy = Math.abs(y1 - y2)
    return Math.sqrt(Math.pow(dx,2) + Math.pow(dy,2));
}

function calcCenter(x1,y2) {

    function middle(p1,p2) {
        return p1 > p2 ? p1 - (p1 - p2) / 2 : p2 - (p2 - p1) / 2;
    }

    return {
        x: middle(x1,x2),y: middle(y1,y2),};
}

function maxOffset(offset,windowDimension,imageDimension) {
    let max = windowDimension - imageDimension;
    if (max >= 0) {
        return 0;
    }
    return offset < max ? max : offset;
}

function calcOffsetByZoom(width,height,imageWidth,imageHeight,zoom) {
    let xDiff = imageWidth * zoom - width;
    let yDiff = imageHeight * zoom - height;
    return {
        left: -xDiff/2,top: -yDiff/2,}
}

class ZoomableImage extends Component {

    constructor(props) {
        super(props);

        this._onLayout = this._onLayout.bind(this);

        this.state = {
            zoom: null,minZoom: null,layoutKNown: false,isZooming: false,isMoving: false,initialdistance: null,initialX: null,initalY: null,offsetTop: 0,offsetLeft: 0,initialTop: 0,initialLeft: 0,initialTopWithoutZoom: 0,initialLeftWithoutZoom: 0,initialZoom: 1,top: 0,left: 0
        }
    }

    processpinch(x1,y2) {
        let distance = calcdistance(x1,y2);
        let center = calcCenter(x1,y2);

        if (!this.state.isZooming) {
            let offsetByZoom = calcOffsetByZoom(this.state.width,this.state.height,this.props.imageWidth,this.props.imageHeight,this.state.zoom);
            this.setState({
                isZooming: true,initialdistance: distance,initialX: center.x,initialY: center.y,initialTop: this.state.top,initialLeft: this.state.left,initialZoom: this.state.zoom,initialTopWithoutZoom: this.state.top - offsetByZoom.top,initialLeftWithoutZoom: this.state.left - offsetByZoom.left,});

        } else {
            let touchZoom = distance / this.state.initialdistance;
            let zoom = touchZoom * this.state.initialZoom > this.state.minZoom
                ? touchZoom * this.state.initialZoom : this.state.minZoom;

            let offsetByZoom = calcOffsetByZoom(this.state.width,zoom);
            let left = (this.state.initialLeftWithoutZoom * touchZoom) + offsetByZoom.left;
            let top = (this.state.initialTopWithoutZoom * touchZoom) + offsetByZoom.top;

            this.setState({
                zoom: zoom,left: 0,left: left > 0 ? 0 : maxOffset(left,this.state.width,this.props.imageWidth * zoom),top: top > 0 ? 0 : maxOffset(top,this.props.imageHeight * zoom),});
        }
    }

    processtouch(x,y) {

        if (!this.state.isMoving) {
            this.setState({
                isMoving: true,initialX: x,initialY: y,});
        } else {
            let left = this.state.initialLeft + x - this.state.initialX;
            let top = this.state.initialTop + y - this.state.initialY;

            this.setState({
                left: left > 0 ? 0 : maxOffset(left,this.props.imageWidth * this.state.zoom),this.props.imageHeight * this.state.zoom),});
        }
    }

    _onLayout(event) {
        let layout = event.nativeEvent.layout;

        if (layout.width === this.state.width
            && layout.height === this.state.height) {
            return;
        }

        let zoom = layout.width / this.props.imageWidth;

        let offsetTop = layout.height > this.props.imageHeight * zoom ?
            (layout.height - this.props.imageHeight * zoom) / 2
            : 0;

        this.setState({
            layoutKNown: true,width: layout.width,height: layout.height,zoom: zoom,offsetTop: offsetTop,minZoom: zoom
        });
    }

    componentwillMount() {
        this._panResponder = PanResponder.create({
            onStartShouldSetPanResponder: (evt,gestureState) => true,onStartShouldSetPanResponderCapture: (evt,onMoveShouldSetPanResponder: (evt,onMoveShouldSetPanResponderCapture: (evt,onPanResponderGrant: (evt,gestureState) => {},onPanResponderMove: (evt,gestureState) => {
                let touches = evt.nativeEvent.touches;
                if (touches.length == 2) {
                    let touch1 = touches[0];
                    let touch2 = touches[1];

                    this.processpinch(touches[0].pageX,touches[0].pageY,touches[1].pageX,touches[1].pageY);
                } else if (touches.length == 1 && !this.state.isZooming) {
                    this.processtouch(touches[0].pageX,touches[0].pageY);
                }
            },onPanResponderTerminationRequest: (evt,onPanResponderRelease: (evt,gestureState) => {
                this.setState({
                    isZooming: false,isMoving: false
                });
            },onPanResponderTerminate: (evt,onShouldBlockNativeResponder: (evt,});
    }

    render() {
        return (
          <View
            style={this.props.style}
            {...this._panResponder.panHandlers}
            onLayout={this._onLayout}>
             <Image style={{
                    position: 'absolute',top: this.state.offsetTop + this.state.top,left: this.state.offsetLeft + this.state.left,width: this.props.imageWidth * this.state.zoom,height: this.props.imageHeight * this.state.zoom
             }}
             source={this.props.source} />
          </View>
        );
    }

}

ZoomableImage.propTypes = {
  imageWidth: PropTypes.number.isrequired,imageHeight: PropTypes.number.isrequired,source: PropTypes.object.isrequired,};
export default ZoomableImage;

原文地址:https://www.jb51.cc/react/301316.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐