Giter Club home page Giter Club logo

react-native-image-zoom's Introduction

REACT NATIVE IMAGE ZOOM

npm NPM npm peer dependency version npm peer dependency version npm bundle size npm npms.io (final) GitHub issues

A performant and customizable image zoom component
built with Reanimated v2+ and TypeScript. ๐ŸŒƒ ๐Ÿš€

Demo:

React Native Image Zoom

Photo by Walling on Unsplash

Features

  • Smooth Zooming Gestures: Ensure smooth and responsive zooming functionality, allowing users to easily zoom in and out of images using intuitive pinch and pan gestures.

  • Reset Zoom and Snap Back: The component automatically resets zoom and snaps back to the initial position when the gesture ends.

  • Double Tap to Zoom: Enable a double tap gesture for users to seamlessly zoom in and out of images. When double tap functionality is enabled, the automatic Reset Zoom and Snap Back feature will be disabled, allowing users to maintain their desired zoom level without automatic resets.

  • Single Tap Functionality: Detect and process single tap gestures to trigger specific actions or functionality as needed within the component

  • Customizable Zoom Settings: Utilize minScale, maxScale, and doubleTapScale props for precise control over minimum, maximum, and double tap zoom levels, tailoring the zoom behavior to application requirements

  • Customizable Functionality: Fine-tune the component's behavior with minPanPointers and maxPanPointers props to define the range of pointers necessary for pan gesture detection. Enable or disable features such as panning (isPanEnabled), pinching (isPinchEnabled), single tap handling (isSingleTapEnabled), and double tap zoom (isDoubleTapEnabled) based on specific application needs.

  • Interactive Callbacks: The component provides interactive callbacks such as onInteractionStart, onInteractionEnd, onPinchStart, onPinchEnd, onPanStart, onPanEnd, onSingleTap, onDoubleTap and onResetAnimationEnd that allow you to handle image interactions.

  • Ref Handle: Customize the functionality further by utilizing the exposed reset method. This method allows you to programmatically reset the image zoom as a side effect to another user action or event, in addition to the default double tap and pinch functionalities.

  • Reanimated Compatibility: Compatible with Reanimated v2 & Reanimated v3, providing optimized performance and smoother animations during image manipulations`.

  • TypeScript Support: Developed with TypeScript to enhance codebase maintainability and ensure type safety, reducing potential errors during development and refactoring processes

  • Full React Native Image Props Support: The component supports all React Native Image props, making it easy to integrate with existing code and utilize all the features that React Native Image provides.

Getting Started

To use the ImageZoom component, you first need to install the package via npm or yarn. Run either of the following commands:

npm install @likashefqet/react-native-image-zoom
yarn add @likashefqet/react-native-image-zoom

Caution

๐Ÿšจ

Please note that this library is compatible with Reanimated v2 & Reanimated v3 and uses GestureHandler v2.

If you haven't installed Reanimated and Gesture Handler yet, please follow the installation instructions for Reanimated and Gesture Handler.

Note

On Android RNGH does not work by default because modals are not located under React Native Root view in native hierarchy. To fix that, components need to be wrapped with gestureHandlerRootHOC (it's no-op on iOS and web).

Usage

First, import the ImageZoom component from the @likashefqet/react-native-image-zoom library:

import { ImageZoom } from '@likashefqet/react-native-image-zoom';

To use the ImageZoom component, simply pass the uri prop with the URL of the image you want to zoom:

Basic Example

<ImageZoom uri={imageUri} />

Customized Example

<ImageZoom
  ref={imageZoomRef}
  uri={imageUri}
  minScale={0.5}
  maxScale={5}
  doubleTapScale={3}
  minPanPointers={1}
  isSingleTapEnabled
  isDoubleTapEnabled
  onInteractionStart={() => {
    console.log('onInteractionStart');
    onAnimationStart();
  }}
  onInteractionEnd={() => console.log('onInteractionEnd')}
  onPanStart={() => console.log('onPanStart')}
  onPanEnd={() => console.log('onPanEnd')}
  onPinchStart={() => console.log('onPinchStart')}
  onPinchEnd={() => console.log('onPinchEnd')}
  onSingleTap={() => console.log('onSingleTap')}
  onDoubleTap={(zoomType) => {
    console.log('onDoubleTap', zoomType);
    if (zoomType === ZOOM_TYPE.ZOOM_IN) {
      onAnimationStart();
      setTimeout(() => {
        imageZoomRef.current?.reset();
      }, 3000);
    }
  }}
  style={styles.image}
  onResetAnimationEnd={(finished) => {
    onAnimationEnd(finished);
  }}
  resizeMode="cover"
/>

Properties

ImageZoom Props

All React Native Image Props &

Property Type Default Description
uri String '' (empty string) The image's URI, which can be overridden by the source prop.
minScale Number 1 The minimum scale allowed for zooming.
maxScale Number 5 The maximum scale allowed for zooming.
doubleTapScale Number 3 The value of the image scale when a double-tap gesture is detected.
minPanPointers Number 2 The minimum number of pointers required to enable panning.
maxPanPointers Number 2 The maximum number of pointers required to enable panning.
isPanEnabled Boolean true Determines whether panning is enabled within the range of the minimum and maximum pan pointers.
isPinchEnabled Boolean true Determines whether pinching is enabled.
isSingleTapEnabled Boolean false Enables or disables the single tap feature.
isDoubleTapEnabled Boolean false Enables or disables the double tap feature. When enabled, this feature prevents automatic reset of the image zoom to its initial position, allowing continuous zooming. To return to the initial position, double tap again or zoom out to a scale level less than 1.
onInteractionStart Function undefined A callback triggered when the image interaction starts.
onInteractionEnd Function undefined A callback triggered when the image interaction ends.
onPinchStart Function undefined A callback triggered when the image pinching starts.
onPinchEnd Function undefined A callback triggered when the image pinching ends.
onPanStart Function undefined A callback triggered when the image panning starts.
onPanEnd Function undefined A callback triggered when the image panning ends.
onSingleTap Function undefined A callback triggered when a single tap is detected.
onDoubleTap Function undefined A callback triggered when a double tap gesture is detected.
onResetAnimationEnd Function undefined A callback triggered upon the completion of the reset animation. It accepts two parameters: finished and values. The finished parameter evaluates to true if all animation values have successfully completed the reset animation; otherwise, it is false, indicating interruption by another gesture or unforeseen circumstances. The values parameter provides additional detailed information for each animation value.

ImageZoom Ref

Property Type Description
reset Function Resets the image zoom, restoring it to its initial position and scale level.

Changelog

Please refer to the Releases section on the GitHub repository. Each release includes a detailed list of changes made to the library, including bug fixes, new features, and any breaking changes. We recommend reviewing these changes before updating to a new version of the library to ensure a smooth transition.

Troubleshooting

Not working on android?

Usage with modals on Android

Author



Shefqet Lika
๐Ÿ’ป commits

Support

For ongoing maintenance and updates, your support is greatly appreciated

Buy Me A Coffee

If you need further assistance, feel free to reach out to me by email at @likashefi.

License

The library is licensed under the MIT License.

react-native-image-zoom's People

Contributors

demedos avatar likashefqet avatar ubugnu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

react-native-image-zoom's Issues

Simple onPress handler?

Is is possible to get an event for a simple onPress? Like, if the image is just tapped once?

onSnapBackEnd / onResetEnd

Is your feature request related to a problem? Please describe.
I am conditionally displaying elements over the image component: they disappear as soon as there is zoom-interaction and reappear after. But currently they already appear once the finger-interaction ends and it would look much better if they would only reappear once the image is fully reset to its initial position.

Describe the solution you'd like
The same callback as all the other on...End functions but called once the image is fully reset to its initial position.

This little add-on would be amazing and much appreciated if its not too much effort as it would greatly improve the UX

Request to support ImageBackground and doubleTap feature

I need to display multiple images overlayed onto a base image. I would like to be able to zoom in and out on the group of images as a whole.

Maybe pass in the base image via uri or source like usual. Then, perhaps pass in an array of Animate.Image components as children.

So ImageZoom.tsx might look like this:

const AnimatedImageBackground = Animated.createAnimatedComponent(ImageBackground)
return (
    <GestureDetector gesture={gestures}>
      <Animated.View onLayout={onImageLayout}>
        <AnimatedImageBackground 
          style={[styles.image, style, animatedStyle]}
          source={{ uri }}
          resizeMode="contain"
          {...props}
        >
          {children}
        </AnimatedImageBackground> 
      </Animated.View>
    </GestureDetector>
);

And then the usage might look like this:

const overlayImages = images.map((image, index) => {
   return <Animated.Image resizeMode='contain' source={image} style={{ position: 'absolute'}} />
})

return (    
  <GestureHandlerRootView>
        <ImageZoom
          style={S.baseImageStyle}
          source={baseImage}
          isDoubleTapEnabled={true}>
             {overlayImages}
        </ImageZoom>
  </GestureHandlerRootView>
)

Support for expo-image or other components

Is your feature request related to a problem? Please describe.
expo-image is beginning to take over <Image/> component from react native.

Describe the solution you'd like
Instead of making a new exported component maybe we could implement a createZoomComponent, which would make any kind of component zoomable, with your current implementation.

Then you could go:

import { createZoomComponent } from 'react-native-image-zoom'
import { Image }ย from 'expo-image'

const ZoomableImage = createZoomComponent(Image)

const MyComponent = () => {
    return <ZoomableImage 
         // ...expo-image props here
    />
}

Describe alternatives you've considered
Another way would be to implement a <ZoomableView>{children}</ZoomableView> kind of component that could just make any child component zoomable.

ResizeMode for Image

Is your feature request related to a problem? Please describe.
Currently there is no option for the resizeMode of the underlaying image component. So in my case if i make a shared element transition from an image element to the ZoomImage the resizeMode changes and therefor the look of the image.

Describe the solution you'd like
Add the prop resizeMode to set the Image resizeMode.

Is it working on expo?

I wonder if this library works on expo? I tried to put it on expo but without success. this library doesn't work there i can't move the photo at all

ExceptionsManager.js:184 TypeError: (0 , _reactNativeReanimated.useSharedValue) is not a function

Describe the bug
When trying to use this plugin I get the following error:
ExceptionsManager.js:184 TypeError: (0 , _reactNativeReanimated.useSharedValue) is not a function

I assume this plugin requires a specific minimum version of react maybe? would be good to specify in the readme

To Reproduce
Install the plugin, run the example

Expected behavior
It shoould work

Smartphone (please complete the following information):

  • Device: iPhone 13 Pro
  • React Native 0.66.5

in modal is not working

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Not Working on android

Describe the bug
I have already integrated the reanimated and gesture handler and both are working on android. But on android its showing the image but its not reacting to the gesture on the image for example pinch to zoom although everything is working fine on ios.

<ImageZoom uri={imagePath} />

Feature Request: Implement 'Snap Back' prop for Zoom Functionality

Is your feature request related to a problem? Please describe.
When using the zoom feature, it automatically zooms back out after zooming in, which can be frustrating when wanting to focus on a specific area for a longer duration.

Describe the solution you'd like
Introduce a "snap back" property that retains the zoom level even after zooming in, ensuring that the view remains at the zoomed-in level until intentionally zoomed out by the user. The default setting for this property should be 'true'.

Describe alternatives you've considered
One alternative solution might be implementing a toggle button that allows users to manually lock the zoom level once they've zoomed in, preventing the automatic zoom-out behavior. However, the proposed "snap back" property would offer a more seamless and user-friendly experience.

Additional context
This feature is especially beneficial for tasks that involve detailed examination or precise adjustments in a particular area. It improves user control and enhances the user experience when focusing on specific elements without constant readjustment due to automatic zoom-out behavior.

Type declarations.ts

I'm using Typescript for my React Native project and after isntall the package I got this warning:

Cannot find module '@likashefqet/react-native-image-zoom' or its corresponding type declarations.ts

Setting state drops the pinch on android when using onInteraction function

Describe the bug
Hi,
Your library is great and smooth. I am having one problem, on android I want to do dispatch action on pinch start and dispatch action on pinch end, which is creating issue of dropping pinch.
Below are the code sample:

  const onInteractionStart = () => {
    if (isIOS()) {
      dispatch(isImageZoomedAction(true));
    }
    progress.stopAnimation(() =>
      Animated.timing(fadeAnim, {
        toValue: 0,
        duration: 100,
        useNativeDriver: true,
      }).start(),
    );
  };

  const onInteractionEnd = () => {
    if (isIOS()) {
      dispatch(isImageZoomedAction(false));
    }

    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 100,
      useNativeDriver: true,
    }).start(() => {
      startAnimation();
    });
  };
  
            <ImageZoomPan
            uri={content[current].image}
            activityIndicatorProps={{
              color: COLOR_SECONDARY,
            }}
            onInteractionStart={onInteractionStart}
            onInteractionEnd={onInteractionEnd}
            minScale={0.5}
            onLoadEnd={() => start()}
            resizeMode={isFullScreen ? 'cover' : 'center'}
          />

Cannot find module '@likashefqet/react-native-image-zoom' or its corresponding type declarations.ts(2307)

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Android: Pinch gesture moves picture to the top-left corner

Describe the bug
When I do pinch gesture then a picture moves to the top left corner direction. The most annoying is pinching in the bottom right area. See the gif below...

My code:

<ImageZoom uri={uri} />

To Reproduce
Steps to reproduce the behavior:

  1. Pinch somewhere in the bottom right area
  2. See how it's moves to the top-left corner

Expected behavior
Pinching should act symmetrical in every area of the picture

Screenshots
ScreenRecorder_20220801-111219

[Feature Request] Disable Snap Back via a dedicated property.

Is your feature request related to a problem? Please describe.
Our app has inconsistent sized image (by design) and this package makes it super easy to handle all the zooming etc. However the "snap back to level 1" feature after about 1s is frustrating users who are zooming in to inspect imagery then being taken back zoomed out, Currently they have to keep their fingers on the screen to try and inspect them which can be a pain, so we'd like to make this a smoother experience for them.

Describe the solution you'd like
It would be great to have a standalone prop that could simply disable the snapping back feature e.g. snapBack={ true/false } as this would solve all our problems.

Describe alternatives you've considered
We've looked at the isDoubleTapEnabled prop which also disables the snap back functionality, however this enables double tap to zoom in/out, which in our scenario conflicts with our "approve" or "unapprove" feature as each time they double tap to approve it, it zooms them out.

Additional context
N/A

Not working on android :<

Describe the bug
Module works great on iOS but I can't get it working on Android :(

To Reproduce
Steps to reproduce the behavior:
Create a component like that:
<ImageZoom resizeMode="contain" minScale={1} maxScale={3} uri={source.uri}/>

and try to pinch on android, nothing happens.

Expected behavior
Properly zooms on android

Screenshots
Can't show it as it's directly connected to pinch

Desktop (please complete the following information):
N/A

Smartphone (please complete the following information):

  • Device: OnePlus Nord
  • OS: Oxygen OS 11.1.11.11.AC01BA
  • Browser - react native app
  • Version [e.g. 22]

Additional context
My package JSON
"dependencies": {
"@expo/config-plugins": "^6.0.1",
"@expo/webpack-config": "^18.0.1",
"@gorhom/bottom-sheet": "^4.4.5",
"@invertase/react-native-apple-authentication": "^2.2.2",
"@likashefqet/react-native-image-zoom": "^1.3.0",
"@react-native-community/netinfo": "9.3.7",
"@react-native-firebase/app": "^17.5.0",
"@react-native-firebase/auth": "^17.5.0",
"@react-native-firebase/database": "^17.5.0",
"@react-native-firebase/firestore": "^17.5.0",
"@react-native-firebase/storage": "^17.5.0",
"@react-navigation/bottom-tabs": "^6.5.5",
"@react-navigation/native": "^6.1.4",
"@react-navigation/stack": "^6.3.16",
"@rneui/base": "^4.0.0-rc.7",
"@rneui/themed": "^4.0.0-rc.7",
"@types/react": "~18.0.27",
"@types/react-native": "~0.70.6",
"@types/react-native-snap-carousel": "^3.8.5",
"base-64": "^1.0.0",
"buffer": "^6.0.3",
"expo": "~48.0.15",
"expo-application": "~5.1.1",
"expo-auth-session": "~4.0.3",
"expo-build-properties": "~0.6.0",
"expo-clipboard": "~4.1.2",
"expo-dev-client": "~2.2.1",
"expo-image-manipulator": "~11.1.1",
"expo-image-picker": "~14.1.1",
"expo-linear-gradient": "~12.1.2",
"expo-random": "~13.1.1",
"expo-secure-store": "~12.1.1",
"expo-splash-screen": "~0.18.2",
"expo-status-bar": "~1.4.4",
"expo-system-ui": "~2.2.1",
"expo-updates": "~0.16.4",
"expo-web-browser": "~12.1.1",
"lodash": "^4.17.21",
"lottie-react-native": "5.1.4",
"md5": "^2.3.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.71.7",
"react-native-chart-kit": "^6.12.0",
"react-native-dotenv": "^3.4.7",
"react-native-dropdown-picker": "^5.4.4",
"react-native-gesture-handler": "~2.9.0",
"react-native-google-mobile-ads": "^9.1.1",
"react-native-image-marker": "^0.6.3",
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-purchases": "^5.13.1",
"react-native-reanimated": "~2.14.4",
"react-native-render-html": "^6.3.4",
"react-native-root-toast": "^3.4.1",
"react-native-safe-area-context": "4.5.0",
"react-native-screens": "~3.20.0",
"react-native-share": "^8.2.1",
"react-native-snap-carousel": "^4.0.0-beta.6",
"react-native-sse": "^1.1.0",
"react-native-svg": "13.4.0",
"react-native-url-polyfill": "^1.3.0",
"react-native-web": "~0.18.11",
"typescript": "^4.9.4",
"zustand": "^4.3.6"
},
"devDependencies": {
"@babel/core": "^7.20.0"
}
`

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

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>
    );

on flick or on pan out callback

It'd be really nice to have an "on flick" gesture that is triggered when the user "flicks" the image (ie to dismiss it). This is similar to a lot of social media apps, ie Twitter.

A stop gap could also be exposing the pan values (start/end) in the onPanEnd callback.

renderLoader is not implemented as stated in the readme.

Describe the bug
renderLoader is not implemented as stated in the readme.

To Reproduce
Steps to reproduce the behavior:

<ImageZoom
  uri={image}
  renderLoader={() => <LoaderScreen loaderColor={Colors.primary} />

Expected behavior
renderLoader should be implemented.

Screenshots
If applicable, add screenshots to help explain your problem.
Screenshot 2023-08-10 at 09 45 22

Additional context
Related to this commit 8f76051

onPress handler event using Gesture.Exclusive

Hi! ๐Ÿ‘‹ @likashefqet
Firstly, thanks for your work on this project! ๐Ÿ™‚

Today I used patch-package to patch @likashefqet/[email protected] for the project I'm working on.

**getting an event for a simple onPress as requested on issue #36 **

<ImageZoom
  uri={imageUri}
  minScale={0.5}
  maxScale={3}
  onInteractionStart={() => console.log('Interaction started')}
  onInteractionEnd={() => console.log('Interaction ended')}
  onPinchStart={() => console.log('Pinch gesture started')}
  onPinchEnd={() => console.log('Pinch gesture ended')}
  onPanStart={() => console.log('Pan gesture started')}
  onPanEnd={() => console.log('Pan gesture ended')}
  onResetAnimationEnd={() => console.log('Reset animation ended')}
  onPress={(event) => {console.log("event", event)}}
  resizeMode="cover"
/>

how i solved it

i passed the doubleTapGesture and onetapGesture to an ExclusiveGesture
Here is the diff that solved my problem:

diff --git a/node_modules/@likashefqet/react-native-image-zoom/lib/typescript/ImageZoom.d.ts b/node_modules/@likashefqet/react-native-image-zoom/lib/typescript/ImageZoom.d.ts
index f33d200..3a764ed 100644
--- a/node_modules/@likashefqet/react-native-image-zoom/lib/typescript/ImageZoom.d.ts
+++ b/node_modules/@likashefqet/react-native-image-zoom/lib/typescript/ImageZoom.d.ts
@@ -15,6 +15,8 @@ declare const _default: React.ForwardRefExoticComponent<Omit<import("react-nativ
     onPinchEnd?: Function | undefined;
     onPanStart?: Function | undefined;
     onPanEnd?: Function | undefined;
+    onPress?: Function | undefined;
+    ExclusiveTapGestures?: never[] | undefined;
     source?: import("react-native").ImageSourcePropType | undefined;
 } & React.RefAttributes<unknown>>;
 export default _default;
diff --git a/node_modules/@likashefqet/react-native-image-zoom/src/ImageZoom.tsx b/node_modules/@likashefqet/react-native-image-zoom/src/ImageZoom.tsx
index 08ae41f..f3b626e 100644
--- a/node_modules/@likashefqet/react-native-image-zoom/src/ImageZoom.tsx
+++ b/node_modules/@likashefqet/react-native-image-zoom/src/ImageZoom.tsx
@@ -31,6 +31,7 @@ export default forwardRef(function ImageZoom(
     onPinchEnd,
     onPanStart,
     onPanEnd,
+    onPress,
     onLayout,
     style = {},
     ...props
@@ -56,6 +57,7 @@ export default forwardRef(function ImageZoom(
     onPinchEnd,
     onPanStart,
     onPanEnd,
+    onPress,
   });
 
   useImperativeHandle(
diff --git a/node_modules/@likashefqet/react-native-image-zoom/src/hooks/useGestures.ts b/node_modules/@likashefqet/react-native-image-zoom/src/hooks/useGestures.ts
index f41c61c..98f200e 100644
--- a/node_modules/@likashefqet/react-native-image-zoom/src/hooks/useGestures.ts
+++ b/node_modules/@likashefqet/react-native-image-zoom/src/hooks/useGestures.ts
@@ -36,7 +36,8 @@ export const useGestures = ({
   onPinchEnd,
   onPanStart,
   onPanEnd,
-}: ImageZoomUseGesturesProps) => {
+  onPress,
+}: ImageZoomUseGesturesProps ) => {
   const isInteracting = useRef(false);
   const isPanning = useRef(false);
   const isPinching = useRef(false);
@@ -131,6 +132,8 @@ export const useGestures = ({
     }
   };
 
+
+
   const onPinchStarted = () => {
     onInteractionStarted();
     isPinching.current = true;
@@ -149,12 +152,17 @@ export const useGestures = ({
     onPanStart?.();
   };
 
+  const onPressed = (e) => {
+    onPress?.(e);
+  }
+
   const onPanEnded = () => {
     isPanning.current = false;
     onPanEnd?.();
     onInteractionEnded();
   };
 
+
   const panGesture = Gesture.Pan()
     .enabled(isPanEnabled)
     .minPointers(minPanPointers)
@@ -172,6 +180,8 @@ export const useGestures = ({
       runOnJS(onPanEnded)();
     });
 
+   
+
   const pinchGesture = Gesture.Pinch()
     .enabled(isPinchEnabled)
     .onStart(
@@ -220,6 +230,17 @@ export const useGestures = ({
       }
     );
 
+
+    const onetapGesture = Gesture.Tap()
+    .numberOfTaps(1)
+    .maxDuration(250)
+    .onStart(
+      (event: GestureStateChangeEvent<TapGestureHandlerEventPayload>)=>{
+        runOnJS(onPressed)(event);
+      }
+    )
+
+    
   const animatedStyle = useAnimatedStyle(() => ({
     transform: [
       { translateX: translate.x.value },
@@ -231,8 +252,9 @@ export const useGestures = ({
   }));
 
   const simultaneousGestures = Gesture.Simultaneous(pinchGesture, panGesture);
+  const tapGesture = Gesture.Exclusive(doubleTapGesture, onetapGesture);
   const gestures = isDoubleTapEnabled
-    ? Gesture.Race(doubleTapGesture, simultaneousGestures)
+    ? Gesture.Race(tapGesture, simultaneousGestures)
     : simultaneousGestures;
 
   return { gestures, animatedStyle, reset };
diff --git a/node_modules/@likashefqet/react-native-image-zoom/src/types.ts b/node_modules/@likashefqet/react-native-image-zoom/src/types.ts
index 62dd3ce..e898024 100644
--- a/node_modules/@likashefqet/react-native-image-zoom/src/types.ts
+++ b/node_modules/@likashefqet/react-native-image-zoom/src/types.ts
@@ -68,6 +68,9 @@ export type ImageZoomProps = Omit<ImageProps, 'source'> & {
    * A callback triggered when the image panning ends.
    */
   onPanEnd?: Function;
+
+  onPress?: Function;
+
   /**
    * @see https://facebook.github.io/react-native/docs/image.html#source
    * @default undefined
@@ -136,4 +139,5 @@ export type ImageZoomUseGesturesProps = Pick<
     | 'onPinchEnd'
     | 'onPanStart'
     | 'onPanEnd'
+    | 'onPress'
   >;

This issue body was partially generated by patch-package.

Is it possible to disable "Reset zoom and snap back to initial position on gesture end"

The title pretty much sums my question/feature request. How can I remove resetting the zoom/pan state when any of the gesture end? I want to be able to continue zooming until maxZoom is reached. I tried removing the code in onFinish, but with no success.

Also, I am interested in using this zoom functionality with other <View>s besides <Image>, would you be open to a PR with such functionality?


Edit: I am able to preserve last zoomed value, but not position by introducing a new:

const lastScale = useSharedValue(1);

//...
const pinchHandler = useAnimatedGestureHandler({
  //...
  onActive: event => {
  //...
  scale.value = clamp(event.scale * lastScale.value, minScale, maxScale);
  //...
  },
  
  onFinish: () => {
  //...
  lastScale.value = scale.value;
  //...
  }
})

Loading indicator "flashes" up when an image has already been loaded

Describe the bug
The loading indicator renders always, causing it to flash and disappear quickly when an image has already been downloaded because const [isLoading, setIsLoading] = useState(true); is set to true on mount and immediately set to false in onLoadEnd.

To Reproduce
Steps to reproduce the behavior:

  1. Render the ImageZoom component
  2. Unmount it and then re-render it
  3. The loading spinner will quickly flash, even though the image is resolved immediately.

Expected behavior
I'd expect the loader to not show at all as the image has been already loaded once.

Smartphone (please complete the following information):

  • iOS iPhone 13

Additional context

Something like this seems to work. Whilst just an idea, maybe there are other better ways to determine whether the loading state should be initially set to true instead of just on mount?

  const [isLoading, setIsLoading] = useState<boolean | undefined>(undefined);
  ...
  const onImageLoadStart = () => {
    // Defer setting the loading state to true slightly to give
    // onLoadEnd time to set the state to false if it already loaded.
    setTimeout(() => {
      setIsLoading((prev) => {
        // If not yet set to a value, we know for sure
        // the image has not loaded, so set loading
        // state to true.
        if (prev === undefined) {
          return true
        }
        return prev
      });
    }, 0)
  };
  ...
  <AnimatedImage onLoadStart={onImageLoadStart} />

Moving the image around requires two fingers when used with react-native-snap-carousel

To move the image around the screen, is required to use two fingers simultaneously, as if the user would be panning, but not actually resizing the image. This problem happens in both android and iOS. Ideally, the user will use only one finger to move the image around.

A quick search in the RN documentation didnt brought anything about multiple touches inside a flatlist.

Get the current scale/zoom level?

Is there a good way to be able to read the current scale whenever I need to? I don't see it on the ref, and I do see that there's a scale = useSharedValue() in the instance but can't find a way to get at it. I have a few places where I would like to be able to read out the current scale (and probably the x and y offsets), so I can save them for later.

I have a PR in for adding the scale to the onPinchEnd callback as a potential fix for one of my specific issues, but putting this note in in case there's a good way to accomplish this now that I'm missing.

Can it work with Lottie?

Hi thanks for the great work! Just to check can this component work with Lottie as loader?

renderLoader={() => }
doesn't seems to work?

Nothing is rendering on android

Describe the bug
Upgrading from v1* to v2* makes all the content vanish, when used as a tag renderer for React native render html

To Reproduce
When used as a custom image tag renderer, the component is working with version 1.2.1 but displays nothing in version 2.0.
It is integrated into React native render html as follows:

....
        img: (args) => {
            const attrs = args.tnode?.init?.domNode?.attribs;
            return ( //todo try with InternalRenderer or TDefaultRenderer
                <RenderHTMLImage
                    uri={attrs.src}
                    // onPress={(uri) => {
                    //     options.dispatch(setLightbox(attrs.src))
                    // }}
                    imagesMaxWidth={args.sharedProps?.computeEmbeddedMaxWidth(Math.min(deviceWidth - 30, Number.parseInt(attrs.width)), "img")}
                />
            )
        },

....
    const RenderHTMLImage = ({ uri, onPress, imagesMaxWidth }) => {
        const [ imageSize, setImageSize ] = useState({})

        useEffect(() => {
            Image.getSize(uri, (width, height) => {
                setImageSize({
                    width,
                    height,
                    aspectRatio: Number((width / height).toFixed(2)),
                })
            })
        }, [])

        return (
            <View
                style={{
                    width: imageSize.width > imagesMaxWidth
                        ? imagesMaxWidth
                        : imageSize.width,
                }}
            >
                <ImageZoom uri={uri}
                           //containerStyle={}
                           imageContainerStyle={{
                        width: imageSize.width > imagesMaxWidth
                            ? imagesMaxWidth
                            : imageSize.width,
                        aspectRatio: imageSize.aspectRatio,
                        resizeMode: 'contain',
                    }}/>
            </View>
        )
    }
....

    return <RenderHTML
            computeEmbeddedMaxWidth={(contentWidth, tagName) => {
                return contentWidth - rightOffset;
            }}
            ignoredStyles={['display', 'width', 'height', 'padding']}
            enableExperimentalMarginCollapsing
            renderers={renderers}
            ...
   
            renderersProps={{
                img: {
                    enableExperimentalPercentWidth: false,
                },
               ...
            }}
        />;

Downgrading helps, but then with react native 72 the app crashes when scrolling.

Expected behavior
The image is shown and rendering.

Desktop (please complete the following information):

  • OS: Windows (building for android)
  • Browser: chrome
  • Version: 116.0.5845.141

Smartphone (please complete the following information):

  • Device: xiaomi redmi note 10s
  • OS: android 13 (miui14.0.2)
  • Browser: chrome
  • Version: 116.0.5845.141

Additional context

{
  npm: '8.11.0',
  node: '16.16.0',
  v8: '9.4.146.24-node.21',
  uv: '1.43.0',
  zlib: '1.2.11',
  brotli: '1.0.9',
  ares: '1.18.1',
  modules: '93',
  nghttp2: '1.47.0',
  napi: '8',
  llhttp: '6.0.7',
  openssl: '1.1.1q+quic',
  cldr: '40.0',
  icu: '70.1',
  tz: '2021a3',
  unicode: '14.0',
  ngtcp2: '0.1.0-DEV',
  nghttp3: '0.1.0-DEV'
}

and


"@likashefqet/react-native-image-zoom": "^2.1.0",
"react-native": "0.72.4",
"react-native-render-html": "^6.3.4",

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.