Skip to content

Keep a bounded gesture area's content on screen - #173

Merged
simonhamp merged 1 commit into
mainfrom
feat/gesture-area-bounded
Oct 24, 2026
Merged

simonhamp merged 1 commit into
mainfrom
feat/gesture-area-bounded

Conversation

@simonhamp

@simonhamp simonhamp commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

The iOS and Android side of bounded and content-ratio on <native:gesture-area> (the element change is NativePHP/mobile-air#603).

With bounded set, on both platforms:

  • Pan is limited to (scale * content - area) / 2 each way, per axis. The content is the area, or content-ratio fitted inside it. An axis where the zoomed content fits has a limit of zero, so it stays centred.
  • A drag past the limit moves with resistance. iOS uses UIScrollView's rubber band formula and Android uses the same one, so the two feel alike.
  • When the finger lifts, or a pinch ends with the content out of place, the pan springs back inside the limit over 350 ms. At 1x that means back to the centre.
  • A pinch zooms around the point between the fingers, and two fingers pan together while pinching. The one-finger drag is ignored while two fingers are down, because it only follows the first finger and made the content drift during a pinch.
  • @dragEnd reports where the pan will come to rest, not where the finger let go.

Things a reviewer might wonder about:

  • On iOS a bounded area uses a UIKit UIPinchGestureRecognizer (through UIGestureRecognizerRepresentable, like the swipe recognizer) instead of MagnifyGesture. MagnifyGesture only gives the location where the pinch started, so it can't follow the fingers.
  • The iOS spring back writes the store from a CADisplayLink. A withAnimation write doesn't work here because NodeAnimationModifier applies .animation(nil, value:) to bound transforms. On Android it's Compose's animate.
  • A gesture area without bounded takes the same code paths as before.

Tested on an iPhone 16 Pro (iOS 27.2) and a moto g24 (Android 14) in the devnull app's image viewer (NativePHP/dev-null-app#70). On the moto a one-finger drag at 1x trailed the finger with resistance and sprang back to the centre on release. Pinching needs a person on a device, since adb can't do two fingers. Both platforms compile in Debug, and the PHP suite passes.

Docs: NativePHP/nativephp.com#581.

🤖 Generated with Claude Code

Pan stops at the zoomed content's edges and centres an axis it fits on,
drags past an edge meet resistance and spring back on release, and a
pinch zooms around the fingers and pans with them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simonhamp added a commit to ricardovfreixo/dev-null-app that referenced this pull request Oct 24, 2026
Both are drafts (NativePHP/mobile-air#603, NativePHP/mobile-ui#173). Swap
back to dev-main once they're merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simonhamp added a commit to NativePHP/dev-null-app that referenced this pull request Oct 24, 2026
* View commit images natively with zoom and gallery controls

* Use released camera plugin instead of deleted branch

* Remove completed native image viewer roadmap item

* Keep the viewed image on screen: bounded pan, springing back to centre at 1x

* Require the bounded gesture area branches of mobile-air and mobile-ui

Both are drafts (NativePHP/mobile-air#603, NativePHP/mobile-ui#173). Swap
back to dev-main once they're merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Simon <simon.hamp@me.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@simonhamp
simonhamp marked this pull request as ready for review October 24, 2026 02:29
@simonhamp
simonhamp merged commit 86ef0e6 into main Oct 24, 2026
4 checks passed
@simonhamp
simonhamp deleted the feat/gesture-area-bounded branch October 24, 2026 02:31
simonhamp added a commit to NativePHP/dev-null-app that referenced this pull request Oct 24, 2026
…#85)

* Use mobile-air and mobile-ui main again

The bounded gesture area work is merged (NativePHP/mobile-air#603 and
NativePHP/mobile-ui#173), so the app goes back to requiring dev-main of
both, with the same 4.6.0 and 0.8.0 aliases. The dev-main heads have the
same tree as the feature branches #70 locked to, so no code changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Catch the Boost agent files up with main

Merging #83 into #84 by hand skipped the boost:update rerun, so AGENTS.md
was still #83's older copy and .agents/skills only held ui-screenshots.
This reruns it on dev-main of nativephp/mobile, which also adds the
nativephp-agent-loop skill (agents drive native:run, screenshots and the
device log on a simulator themselves) and points the nativephp-mobile
skill at it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant