oblador / react-native-pinchable

Instagram like pinch to zoom for React Native
MIT License
229 stars 26 forks source link

Updating ScrollView content while view is pinched in makes app unresponsive #9

Open CptFabulouso opened 2 years ago

CptFabulouso commented 2 years ago

Hi. We are displaying array of images in ScrollView and if we push new images while the Pinchable component is pinched in, the app is covered with gray overlay, which can't be discarded and makes the app unresponsive.

Here is simple code for reproduction. Launch the app, zoom in and wait for the timeout in useEffect

import React, { useEffect, useState } from 'react'
import { ScrollView, View, Image, Dimensions } from 'react-native'
import Pinchable from 'react-native-pinchable'

export default function App() {
    const [sources, setSources] = useState(
        new Array(20).fill(0).map((_, index) => 'https://picsum.photos/id/' + index + '/200/300'),
    )

    useEffect(() => {
        setTimeout(() => {
            const newSources = new Array(20)
                .fill(0)
                .map((_, index) => 'https://picsum.photos/id/' + (20 + index) + '/200/300')
            setSources(c => [...c, ...newSources])
        }, 5000)
    }, [])

    return (
        <View style={{ flex: 1 }}>
            <ScrollView pinchGestureEnabled={false}>
                {sources.map((image, index) => (
                    <Pinchable key={index} minimumZoomScale={1} maximumZoomScale={3}>
                        <Image
                            style={{ width: Dimensions.get('window').width, height: 300 }}
                            resizeMode="cover"
                            source={{ uri: image }}
                        />
                    </Pinchable>
                ))}
            </ScrollView>
            <View style={{ flex: 1 }} />
        </View>
    )
}

Here is video of the code above:

https://user-images.githubusercontent.com/25827002/170460253-a585d4f0-6d3a-4214-a4fe-725ab5ed9d30.mp4

In the place we are using this Pinchable component it behaves a little bit different and if I try to pinch in (after the error happens), the app crashes with following error.

*** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan nan]. Layer: <CALayer:0x600002bfe420; position = CGPoint (206 448); bounds = CGRect (0 0; 0 0); delegate = <RNPinchableView: 0x143cde530; reactTag: 10717; frame = (nan nan; 0 0); anchorPoint = (inf, inf); gestureRecognizers = <NSArray: 0x60000218e1c0>; layer = <CALayer: 0x600002bfe420>>; sublayers = (<CALayer: 0x60000282cb80>); opaque = YES; allowsGroupOpacity = YES; anchorPoint = CGPoint (inf inf); transform = CATransform3D (1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1); borderColor = (null)>'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010b8c7d70 __exceptionPreprocess + 236
    1   libobjc.A.dylib                     0x0000000108b1614c objc_exception_throw + 56
    2   CoreFoundation                      0x000000010b8c7c40 -[NSException initWithCoder:] + 0
    3   QuartzCore                          0x000000010b517afc -[CALayer setPosition:] + 384
    4   QuartzCore                          0x000000010b5181d8 -[CALayer setFrame:] + 424
    5   UIKitCore                           0x0000000120f7ffa4 -[UIView(Geometry) setFrame:] + 428
    6   ZootMobileApp                       0x0000000103c993f8 -[RNPinchableView handlePinchGesture:] + 1156
    7   UIKitCore                           0x000000012054eee0 -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 52
    8   UIKitCore                           0x000000012055820c _UIGestureRecognizerSendTargetActions + 112
    9   UIKitCore                           0x000000012055511c _UIGestureRecognizerSendActions + 316
    10  UIKitCore                           0x0000000120554720 -[UIGestureRecognizer _updateGestureForActiveEvents] + 632
    11  UIKitCore                           0x0000000120548d90 _UIGestureEnvironmentUpdate + 2036
    12  UIKitCore                           0x0000000120548134 -[UIGestureEnvironment _updateForEvent:window:] + 736
    13  UIKitCore                           0x0000000120a74350 -[UIWindow sendEvent:] + 4304
    14  UIKitCore                           0x0000000120a4c0fc -[UIApplication sendEvent:] + 784
    15  UIKitCore                           0x0000000120ada59c __dispatchPreprocessedEventFromEventQueue + 7720
    16  UIKitCore                           0x0000000120adc620 __processEventQueue + 6764
    17  UIKitCore                           0x0000000120ad4540 __eventFetcherSourceCallback + 184
    18  CoreFoundation                      0x000000010b836234 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
    19  CoreFoundation                      0x000000010b836134 __CFRunLoopDoSource0 + 204
    20  CoreFoundation                      0x000000010b8354c4 __CFRunLoopDoSources0 + 256
    21  CoreFoundation                      0x000000010b82fa18 __CFRunLoopRun + 744
    22  CoreFoundation                      0x000000010b82f218 CFRunLoopRunSpecific + 572
    23  GraphicsServices                    0x000000011173b60c GSEventRunModal + 160
    24  UIKitCore                           0x0000000120a2da98 -[UIApplication _run] + 992
    25  UIKitCore                           0x0000000120a32634 UIApplicationMain + 112
    26  ZootMobileApp                       0x0000000102d43dd0 main + 104
    27  dyld                                0x00000001076b9cd8 start_sim + 20
    28  ???                                 0x000000010740108c 0x0 + 4416606348
    29  ???                                 0x303d000000000000 0x0 + 3475934487399890944
)
libc++abi: terminating with uncaught exception of type NSException
dyld4 config: DYLD_ROOT_PATH=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot DYLD_LIBRARY_PATH=/Users/pavelgric/Library/Developer/Xcode/DerivedData/ZootMobileApp-cwmmojyrqvickmafcfxbhvwcllaw/Build/Products/Debug-iphonesimulator:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/libBacktraceRecording.dylib:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/libMainThreadChecker.dylib:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib DYLD_FRAMEWORK_PATH=/Users/pavelgric/Library/Developer/Xcode/DerivedData/ZootMobileApp-cwmmojyrqvickmafcfxbhvwcllaw/Build/Products/Debug-iphonesimulator
terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan nan]. Layer: <CALayer:0x600002bfe420; position = CGPoint (206 448); bounds = CGRect (0 0; 0 0); delegate = <RNPinchableView: 0x143cde530; reactTag: 10717; frame = (nan nan; 0 0); anchorPoint = (inf, inf); gestureRecognizers = <NSArray: 0x60000218e1c0>; layer = <CALayer: 0x600002bfe420>>; sublayers = (<CALayer: 0x60000282cb80>); opaque = YES; allowsGroupOpacity = YES; anchorPoint = CGPoint (inf inf); transform = CATransform3D (1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1); borderColor = (null)>'
CoreSimulator 802.6.1 - Device: iPhone 11 Pro Max (98939DCB-055B-4061-8565-431AE3AC31D6) - Runtime: iOS 15.5 (19F70) - DeviceType: iPhone 11 Pro Max
yannisdev commented 2 years ago

I have the same experience and a similar error. The error does not happen consistently though. However it only happens on iOS, not on android.

CALayer position contains NaN: [nan nan]. Layer: <CALayer:0x281d10d80; position = CGPoint (212 321); bounds = CGRect (0 0; 0 0); delegate = <RNPinchableView: 0x11a9795f0; reactTag: 5385; frame = (nan nan; 0 0); anchorPoint = (inf, inf); gestureRecognizers = <NSArray: 0x2810e3210>; layer = <CALayer: 0x281d10d80>>; sublayers = (<CALayer: 0x281d5b860>); opaque = YES; allowsGroupOpacity = YES; anchorPoint = CGPoint (inf inf); transform = CATransform3D (1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1); borderColor = (null)> at 0 CoreFoundation 0x000000018abc929c 6B22DD81-3585-3BE6-BC77-BA19810EC0F2 + 627356 at 1 libobjc.A.dylib 0x00000001a38f9744 objc_exception_throw + 60 at 2 CoreFoundation 0x000000018ac20390 6B22DD81-3585-3BE6-BC77-BA19810EC0F2 + 983952 at 3 QuartzCore 0x000000018e894ebc DF21293E-9DBF-37A5-8506-D0C7F3D8646C + 143036 at 4 QuartzCore 0x000000018e94f5fc DF21293E-9DBF-37A5-8506-D0C7F3D8646C + 906748 at 5 QuartzCore 0x000000018e9676c8 DF21293E-9DBF-37A5-8506-D0C7F3D8646C + 1005256 at 6 UIKitCore 0x000000018d135c7c 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1604732 at 7 Solebich 0x0000000100f07a4c -[RNPinchableView handlePinchGesture:] + 1156 at 8 UIKitCore 0x000000018d18be20 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1957408 at 9 UIKitCore 0x000000018d155490 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1733776 at 10 UIKitCore 0x000000018d11e990 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1509776 at 11 UIKitCore 0x000000018d1577d8 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1742808 at 12 UIKitCore 0x000000018d1103ac 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1450924 at 13 UIKitCore 0x000000018d14375c 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1660764 at 14 UIKitCore 0x000000018d150a1c 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1714716 at 15 UIKitCore 0x000000018d2fe6fc 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 3475196 at 16 UIKitCore 0x000000018d124318 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1532696 at 17 UIKitCore 0x000000018d119070 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 1486960 at 18 UIKitCore 0x000000018df6a574 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 16500084 at 19 UIKitCore 0x000000018d786d5c 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 8228188 at 20 UIKitCore 0x000000018de0dedc 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 15072988 at 21 UIKitCore 0x000000018de0d6a4 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 15070884 at 22 CoreFoundation 0x000000018abeb414 6B22DD81-3585-3BE6-BC77-BA19810EC0F2 + 766996 at 23 CoreFoundation 0x000000018abfc1a0 6B22DD81-3585-3BE6-BC77-BA19810EC0F2 + 836000 at 24 CoreFoundation 0x000000018ab35694 6B22DD81-3585-3BE6-BC77-BA19810EC0F2 + 22164 at 25 CoreFoundation 0x000000018ab3b05c 6B22DD81-3585-3BE6-BC77-BA19810EC0F2 + 45148 at 26 CoreFoundation 0x000000018ab4ebc8 CFRunLoopRunSpecific + 600 at 27 GraphicsServices 0x00000001a6cba374 GSEventRunModal + 164 at 28 UIKitCore 0x000000018d4c2b58 137A95AA-DA6D-332C-BC01-E13BB9B6E317 + 5327704 at 29 UIKitCore 0x000000018d244090 UIApplicationMain + 364 at 30 Solebich 0x00000001002fe754 main + 104 at 31 dyld 0x0000000104759da4 start + 520

jslok commented 1 year ago

Any solution?

CptFabulouso commented 1 year ago

Sadly no, I didn't look into it any further. We used following workaroud, but not sure if it's applicable to you. Our use case is that we first load low resolution images and then replace them with high resolution, so to avoid the crash we just disable the zooming feature while the highres images are loading. Partial example code:

<View
    // Disable pinch to zoom until full size images are loaded, otherwise the app may crash
    pointerEvents={highResImagesLoaded ? 'auto' : 'none'}
>
    <Pinchable minZoom={1} maxZoom={3}>
        <Image source={image.source} />
    </Pinchable>
</View>
pierroo commented 1 year ago

I am also facing this issue; anyone found a fix for this? :/