Anthonyzou / react-native-image-zoom

Image pan and zoom for Android
https://www.npmjs.com/package/react-native-image-zoom
MIT License
115 stars 52 forks source link

Prevent scroll on parent view unless edge is met #16

Open FMCorz opened 8 years ago

FMCorz commented 8 years ago

Hi,

I am trying to use react-native-image-zoom within react-native-viewpager but it does not behave exactly the way I would like it to. I am creating this issue out of desperation as I have not found any solution. I am happy to provide a pull request if I am told how to fix this.

The problem I am facing is that a zoom/drag of the image will not capture the touch event, thus causing the viewpager to drag/switch the pages. In the viewpager the panResponder only captures the event if the pager is not locked, in transition, or if the touch direction is vertical. So, I thought that it was easy enough to just lock the pager while the image was being dragged, but that's not that simple. image-zoom does not trigger any event when the image is dragged, only when it is zoomed. Also the onScaleChange event does not report the current scale but some sort of computed scale, making it hard to detect if the image is current being zoomed in.

I patched (will submit a pull request later) the plugin to report when the Matrix changed, hoping that I could use this to determine whether the pager should be allowed to change page, but I'm confused about the values the photoView::onMatrixChange event reports, the width do not match at all the one reported by onLayout (I got 360 vs 1080), is there something I'm missing here? So this solution ended up being a dead end. Not mentioning that it was super hacky as the scrollView of the viewpager tries to steal the responder. See React 1026.

I also thought I could patch the viewpager, but as it cannot know the current state of image-zoom I figured that it was not a good idea, especially as they already offered the locked option which should be enough.

In short, I would like to disable the view pager (understand bubbling of touch events) when the image has been zoomed in, and we're not on an edge. Basically making photoView::setAllowParentInterceptOnEdge work, it seems that it doesn't because React does not allow native events to be intercepted.

Thanks in advance for your help, guidance, and/or feedback.

FMCorz commented 8 years ago

I've managed to find a compromise for now, though it required #17 to be integrated. The following prevents the parent viewpager from stealing the gestures when the image is being zoomed in. Though it does not allow the viewpager from regaining the control when the zoom reaches an edge.

class MyComponent extends Component {
  ...
  componentWillMount() {
   this._imgPanResponder = PanResponder.create({
      onStartShouldSetPanResponder: (e, gestureState) => {
        // Set the image as the element that should answer the event.
        if (gestureState.numberActiveTouches == 2) {
          return true;
        }
      },
      onPanResponderTerminationRequest: (e, gestureState) => {
        // Refuse to give the responder to the parent scrollview.
        return false;
      }
    });
  }
  ...
  render() {
    return (
      <ViewPager
        dataSource={this.state.dataSource}
        renderPage={(pageData, pageId, pageIndex) => {
          const source = {uri: pageData.uri};
          return (
            <ImageZoom
              style={styles.image}
              onMatrixChange={(e) => {
                // Lock the ViewPager when the scale is not 1. In order to work
                // nicely this also requires some PanHandlers.
                var isLocked = Math.round(e.nativeEvent.scale * 1000) / 1000 != 1;
                if (isLocked != this.state.isLocked) {
                  this.setState({isLocked: isLocked});
                }
              }}
              {...this._imgPanResponder.panHandlers}
              source={source} />
          );
        }}
        isLoop={false}
        autoPlay={false}
        renderPageIndicator={false}
        locked={this.state.isLocked}
        style={styles.pager} />
    );
  }
...
}

There is still a little quirk where you can drag for a few pixel, then add an extra finger and start zooming in the image while dragging. Though the frame in which this happens in rather small.

Anthonyzou commented 8 years ago

I think the native viewpager on android would not have these issues. Of course, there is a bug where pinch and zoom will crash the app. This is an issue from the android and PhotoView side. The fix would be to implement the fix suggested by photoview (Issues With ViewGroups). I haven't had time to test and add this to the project.