likashefqet/react-native-image-zoom

Android - Failed to pinch to zoom when ImageZoom is in a Scrollview

mguyard opened this issue · 4 comments

Hello,

I've create a Carousel component who use ImageZoom lib.
All my images are in an horizontal ScrollView.
I've add GestureHandlerRootView before ImageZoom component. Now i can pinch but only vertical. In another direction, it try to swipe.

CleanShot 2022-12-11 at 19 07 55

I don't have this issue on iOS.

Do you have some ideas to resolve this issue ?

return (
        <View style={[styles.container, style]} {...rest}>
            <ScrollView
                pagingEnabled
                horizontal
                decelerationRate="fast"
                scrollEventThrottle={0}
                showsHorizontalScrollIndicator={false}
                onScroll={({ nativeEvent }) => {
                    const layoutWidth = nativeEvent.layoutMeasurement.width;
                    const offset = nativeEvent.contentOffset.x;
                    const currentIndex = Math.ceil(offset / layoutWidth);
                    setIndex(currentIndex);
                }}
            >
                {
                    /* Checking if the slides array is not empty. If it is not empty, it will return the
                    slides array. If it is empty, it will return null. */
                    slides.length > 0
                        ? slides.map((item, key) => {
                            return (
                                <GestureHandlerRootView key={key}>
                                    <ImageZoom
                                        key={key}
                                        /* Checking if the image is horizontal or vertical. If it is
                                        horizontal, it will cover the screen. If it is vertical, it will
                                        contain the image. */
                                        resizeMode={
                                            imagesInfos[
                                                imagesInfos?.findIndex(
                                                    (image) => image.uri === item
                                                )
                                            ]?.orientation == 'horizontal'
                                                ? 'cover'
                                                : 'contain'
                                        }
                                        source={
                                            typeof item === 'string'
                                                ? { uri: item }
                                                : item
                                        }
                                        style={[
                                            { width: screenWidth, flexGrow: 1 },
                                        ]}
                                    />
                                </GestureHandlerRootView>
                            );
                          })
                        : null
                }
                {
                    /* Cloning the children and adding the width of the screen to the style. */
                    React.Children.map(children, (child) => {
                        const s = child?.props?.style || {};
                        return (
                            <View style={{ width: screenWidth }}>
                                {React.cloneElement(child, {
                                    style: { ...s, width: screenWidth },
                                })}
                            </View>
                        );
                    })
                }
            </ScrollView>
            <Pager color={dotColor} index={index} length={itemsLength} />
        </View>
    );

I've also tested with a useState who disable Scroll on pinch :

const handlePinch = (event) => {
        const { scale } = event;
        console.log(event);
        setScrollEnabled(scale === 1);
    }

    return (
        <View style={[styles.container, style]} {...rest}>
            <ScrollView
                pagingEnabled
                horizontal
                decelerationRate="fast"
                scrollEventThrottle={200}
                scrollEnabled={scrollEnabled}
                showsHorizontalScrollIndicator={false}
                onScroll={({ nativeEvent }) => {
                    const layoutWidth = nativeEvent.layoutMeasurement.width;
                    const offset = nativeEvent.contentOffset.x;
                    const currentIndex = Math.ceil(offset / layoutWidth);
                    setIndex(currentIndex);
                }}
            >
                {
                    /* Checking if the slides array is not empty. If it is not empty, it will return the
                    slides array. If it is empty, it will return null. */
                    slides.length > 0
                        ? slides.map((item, key) => {
                            return (
                                <GestureHandlerRootView key={key}>
                                    <PinchGestureHandler onPinchGestureEvent={handlePinch}>
                                        <ImageZoom
                                            key={key}
                                            /* Checking if the image is horizontal or vertical. If it is
                                            horizontal, it will cover the screen. If it is vertical, it will
                                            contain the image. */
                                            resizeMode={
                                                imagesInfos[
                                                    imagesInfos?.findIndex(
                                                        (image) => image.uri === item
                                                    )
                                                ]?.orientation == 'horizontal'
                                                    ? 'cover'
                                                    : 'contain'
                                            }
                                            source={
                                                typeof item === 'string'
                                                    ? { uri: item }
                                                    : item
                                            }
                                            style={[
                                                { width: screenWidth, flexGrow: 1 },
                                            ]}
                                        />
                                    </PinchGestureHandler>
                                </GestureHandlerRootView>
                            );
                          })
                        : null
                }
                {
                    /* Cloning the children and adding the width of the screen to the style. */
                    React.Children.map(children, (child) => {
                        const s = child?.props?.style || {};
                        return (
                            <View style={{ width: screenWidth }}>
                                {React.cloneElement(child, {
                                    style: { ...s, width: screenWidth },
                                })}
                            </View>
                        );
                    })
                }
            </ScrollView>
            <Pager color={dotColor} index={index} length={itemsLength} />
        </View>
    );

but i receive this error

ERROR Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Check the render method of PinchGestureHandler.

If i replace ImageZoom with Image error disappear but not able to zoom :(

I've try to use the onPinchStart and onPinchEnd (didn't see before in doc) to disable scrollEnabled in the ScrollView when i Pinch.
But i can see that on ios, onPinchStart and onPinchEnd correctly trigger but on Android, onPinchEnd is the only triggered but when tap (or click in simulator)

CleanShot 2022-12-11 at 21 00 46

Do you have an idea ?

@mguyard
Please add your GestureHandlerRootView on the top level of your project, unless you use modals, then that should also wrap the modal content. In all other cases, GestureHandlerRootView on the top level of your project should be enough to enable gesture handler anywhere in your project.

Regarding your issue, please create a reproducible demo an I will try to debug it. Meanwhile, to unblock you, maybe try onInteractionStart and onInteractionEnd callbacks instead of onPinchStart and onPinchEnd. Unfortunately, they are not documented properly.

Tip: maybe using react-native-pager-view is a better way to implement a carousel.

@likashefqet,

Thanks. Moving GestureHandlerRootView on top of my NavigationContainer and this working perfectly now.
I big thanks for your help and your amazing lib