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.
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)
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.
Thanks. Moving GestureHandlerRootView on top of my NavigationContainer and this working perfectly now.
I big thanks for your help and your amazing lib