Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make "double tap to zoom" precise across platforms #1482

Merged
merged 2 commits into from
Sep 20, 2023
Merged

Make "double tap to zoom" precise across platforms #1482

merged 2 commits into from
Sep 20, 2023

Conversation

gaearon
Copy link
Collaborator

@gaearon gaearon commented Sep 19, 2023

The problem

On Android, we were zooming in way too hard (#1275). I tried to fix it by zooming in "less", but I wasn't sure what scale and how to calculate the new position in a way that would feel intuitive. I studied what different apps do using a variety of different image sizes (test thread) and settled on the following principles that are mostly inspired by the iOS Photos app:

  • Try to zoom in enough that black bars (if present) disappear, i.e. scale to fill.
  • Try to avoid zooming in too little. (I settled on 2x minimal zoom.)
  • Never zoom in too much. (I settled on disallowing zoom after the original image's pixels become 2x stretched.)
  • Try to keep the point you tapped under your finger. (But avoid going out of bounds — ideally, no black bars after zoom.)

The new behavior is consistent between Android and iOS.

How the code works

Our lightbox appears to be based on a vendored version of https://github.com/jobtoday/react-native-image-viewing. The "double tap to zoom" gesture is implemented separately for Android and iOS:

  • The Android version is implemented in ImageItem.android.ts and usePanResponder.ts. It scales and transforms the original image. When you pinch or double tap, usePanResponder calculates the new scale and transform values so that the image zooms in.

  • The iOS version is in ImageItem.ios.ts and useDoubleTapToZoom.ts. It also scales and transforms the original image. However, that scale and transform are never updated. Instead, it uses iOS UIScrollView for pinching and double-tap. When you double tap, useDoubleTapToZoom calculates the new "zoom rect" and asks the scroll view to zoom into it.

I kept this divergence in the implementation details, so the code looks a bit duplicated (but not quite).

I prefer this piece heavily commented but I'm down to trim it down if it feels like much.

Before / After

Landscape aspect ratio

The original behavior on Android zooms in way too much.

The original behavior on iOS is decent but doesn't use the screen estate very well (black bars).

dril_before.mov

The new behavior consistently fills the screen:

dril_after.mov

Square aspect ratio

Before:

paul_before.mov

After:

paul_after.mov

Portrait aspect ratio

Before (notice the black bar on iOS when zooming in near the top):

kiki_before.mov

After (notice how there's no black bar on iOS when zooming in near the top):

kiki_after.mov

Edge cases

Not recording these, but https://bsky.app/profile/danabra.mov/post/3k7h5zss7bp2g is a good thread for testing.

Interesting edge cases include very tall images, very wide images, squares, high res and low res images.

@simonetthomas
Copy link

Thanks for fixing the issue I opened ! The zoom seems nice in your videos :)

@gaearon
Copy link
Collaborator Author

gaearon commented Sep 20, 2023

thank you for reporting :)

Copy link
Collaborator

@pfrazee pfrazee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is, indeed, no joke. I'm going to approve & merge so I can include it in tonight's testflight. The code at a glance looks fine; all that remains is testing on real devices, which I'll do shortly

@pfrazee pfrazee merged commit d2c253a into main Sep 20, 2023
4 checks passed
@pfrazee pfrazee deleted the img-zoom branch September 20, 2023 02:07
estrattonbailey added a commit that referenced this pull request Sep 20, 2023
* origin:
  Allow touch at the top of the lightbox (#1489)
  Bump ios build number
  Feeds tab fixes (#1486)
  Nicer 'post processing status' in the composer (#1472)
  Inline createPanResponder (#1483)
  Tree view threads experiment (#1480)
  Make "double tap to zoom" precise across platforms (#1482)
  Onboarding recommended follows (#1457)
  Add thread sort settings (#1475)
const willZoom = !scaled
if (willZoom) {
const {pageX, pageY} = event.nativeEvent
nextZoomRect = getZoomRectAfterDoubleTap(pageX, pageY)
}

// @ts-ignore
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just being curious here, what warning is this silencing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably scrollResponderZoomTo not being in the type definitions?

ls1955 added a commit to ls1955/react-native-image-viewing that referenced this pull request Dec 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Double tap zoom on a picture zooms in too much
4 participants