openspacelabs/react-native-zoomable-view

Pinch zoom / pan on ios jittery / stops before gesture complete

Closed this issue · 10 comments

I implemented this component in my app and it works great on android device.

But on IOS when I pinch to zoom it zooms only a little and stops. I have to re pinch and zoom again to get further zoom.
Also it does not recognize panning while pinching like it does on Android.

From the behavior it appears to me that other higher level component is consuming / interfering with the pinch / pan gestures.

I am running the component in a Tab created with the react-navigation/material-top-tabs

I set the Tab option swipeEnabled to false for this tab so I thought that would not interfere with gestures. But something else must be interfering

Any suggestions on how to figure out why it is not zooming / panning smoothly on ios?

Or is there any known compatibility issues running this component in a tab for IOS?

Hi @kmeekva – it sounds as though something is interfering with the gestures as these behaviours should work fine in both iOS and Android.

You may want to try wrapping the component in react-native-gesture-handler to try and catch these events. I know that with native views like Modal views, native gesture handlers can grab the event and take over, and this library helps avoid that.

How exactly would I use the react-native-gesture-handler in this case?

I installed react-native-gesture-handler

Then in my app I imported like this:
import {Gesture, GestureDetector } from 'react-native-gesture-handler'

Do I need to define gestures ( pinch and pan ) and pass them to the Gesturedetector element?

Seems like when that is done you can add actions to fire on the events -- but what I want is for the events to be handled by the zoomable view ( in my sub component )

How do I pass these events to my component ( which has a zoomable view )

I tried this:

      const pinch = Gesture.Pinch();

<GestureDetector gesture={pinch}>
    <my zoomable view componet />
</GestureDetector>

But now pinch does nothing.

Before it was just jittery ( not really jittery -- but would only zoom a little then stop and not allow more zooming or panning without lifting fingers and zooming again )

Seems like I need the gestruredetector to pass the gestures to the subcomponent somehow.

Try wrapping it in its own gesture handler root view, that should stop events bubbling up

I wrapped my component in
<GestureHandlerRootView>
It is slightly more responsive, but pinch zoom still stops after a small zoom amount and cannot continue until you re-pinch.

I think I've narrowed down the issue to be something with the material-top-tabs Tab Navigation that is interfering.

When I take the component out of the tab navigation it works flawlessly.

Anyone know any trick to get material-top-tabs to not grab the gestures?

I've tried setting the swipeEnabled=false (see below config) but is still won't work smoothly

I am using:
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
<Tab.Navigator
swipeEnabled={false}
screenOptions={({ route }) => ({
swipeEnabled: false ,

Sounds like they switched from using react-native-gesture-handler to react-native-pager-view in the material top tab navigator. Some people suggest downgrading. Do you think that could be the issue?

https://reactnavigation.org/docs/upgrading-from-5.x#material-top-tabs-now-uses-viewpager-instead-of-reanimated-and-gesture-handler

5.3.14 @react-navigation/native @ ^5.0.5react @ *react-native @ *react-native-gesture-handler @ >= 1.0.0react-native-reanimated @ >= 1.0.0react-native-tab-view @ >= 2.0.0
6.0.0-next.0 @react-navigation/native @ ^5.0.5react @ *react-native @ *react-native-pager-view @ >= 1.0.0react-native-tab-view @ >= 3.0.0

https://www.npmpeer.dev/packages/@react-navigation/material-top-tabs/compatibility

Possibly - let me know if that helps.

Are you using the very latest version of this library? There is a new prop onShouldBlockNativeResponder that will now work with gesture-handler. It is set to true by default. Merged in the last couple of weeks.

If you wrap your zoomable view in a gesture handler root view, this prop allows the gesture handler to override the gesture system and block native event responders. I was able to use this with an RNScreens modal view with react-navigation.

If that doesn't work, yes - I suspect something in the top tabs view

I was running version 2.1.3

I upgraded to version 2.1.4 but the issue still persists.

Do I need to pass this new prop? Or is it supposed to default to true?
I think the issue is that the react-native/material-top-tabs is using viewPager now no react-native-gesture-handler

So I think both are trying to grab the gestures.

I found viewPager has settings onStartShouldSetResponder and onMoveShouldSetResponder that sound like they should have something to do with bubbling of getsures, but not sure how to use them.

Yeah, I don't know. That depends on how viewPager intercepts events. We've used <PanGestureHandler> as a wrapper for our zoomable view and that worked. Sorry I can't be more help

Well to try to isolate the issue, I created an expo SNAK to try to reproduce the problem with material-top-tabs -- BUT it worked perfectly when I ran the test on my device.

I started investigating the versions of all the libraries the snack was pulling in, and I noticed they were using SDK 48 when I was still using SDK 47.

I did
yarn add expo@^48.0.0
npx expo install --fix
npx expo-doctor

This updated lots of packages and NOW everything works perfectly!

So there is no compatibility issues when everything is up to date.

I see SDK 49 is out -- I'll test that next. But for now things are working so we can close this I think.

There's a bug in the code that defaults onShouldBlockNativeResponder to true, I've fixed this in #77.

@kmeekva in the meantime you can use an onShouldBlockNativeResponder prop with a value of () => true to avoid the issue.