Skip to content

Let a gesture area's pan trigger when let go far enough, on iOS and Android - #197

Merged
simonhamp merged 1 commit into
mainfrom
feat/gesture-area-trigger
Nov 3, 2026
Merged

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

Conversation

@simonhamp

@simonhamp simonhamp commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Renderers for a gesture area pull with a trigger point: pan-x-trigger / pan-y-trigger and on_trigger, from trigger-x / trigger-y and @trigger in NativePHP/mobile-air#651. It's what the dev-null app's swipe-to-reply needs (NativePHP/dev-null-app#157).

On a one-axis pan with a trigger, on both platforms:

  • The pan only starts on a drag the trigger's way. On iOS the UIKit pan's gestureRecognizerShouldBegin also checks the direction, so a drag the other way fails it and goes to the enclosing scroll view or iOS 26's swipe back from mid-screen. On Android a new detectPull leaves the touch slop unconsumed for a drag the other way, which starts the slop check over instead of taking the gesture.
  • It follows the finger from rest to the point, then a third of the finger's movement past it, like the outer snap points. It never goes past rest the other way.
  • Each time it goes out past the point it plays a light haptic: UIImpactFeedbackGenerator(style: .light) on iOS, HapticFeedbackType.GestureThresholdActivate on Android. Coming back under plays nothing.
  • On release it springs back to rest with the snap points' 350 ms ease-out, and fires on_trigger if it was past the point when the finger lifted. A cancelled pan never fires.
  • A PHP write-back on a trigger axis springs, as on a snapping axis.

Anything bound to the same SharedValue follows the pull on the UI thread, so the app can bring an icon in with the finger without PHP.

Testing

GestureAreaTriggerTest in the Robolectric module covers Android: past the point it triggers and springs back, it follows then resists, a short pull and one brought back under the point don't trigger, the haptic plays once per crossing, and a drag the other way scrolls an enclosing scroll container. The existing gesture tests still pass.

In the dev-null app (NativePHP/dev-null-app#157), on an iPhone 17 Pro simulator (iOS 26.2) and an Android 15 emulator: the message follows the finger, the icon tracks it, short pulls only spring back, a vertical drag that starts on a message still scrolls the thread, and on iOS a drag the wrong way on a message still swipes back. An unsigned Release build compiles.

Worth a look: the haptic is untested on hardware, since simulators and emulators don't play them.

🤖 Generated with Claude Code

…ndroid

A bound pan axis with pan-x-trigger / pan-y-trigger (from the gesture
area's trigger-x / trigger-y in mobile-air) is a pull, the swipe-to-reply
pattern:

- it only starts on a drag the trigger's way, so a drag the other way is
  left to an enclosing scroll view or iOS's swipe back;
- it follows the finger from rest to the trigger point, then with a third
  of the finger's movement past it, and never the other way past rest;
- each time it goes out past the point it plays a light haptic
  (UIImpactFeedbackGenerator .light on iOS, GestureThresholdActivate on
  Android), and coming back under plays nothing;
- on release it springs back to rest with the snap points' 350 ms
  ease-out, and fires on_trigger (a PRESS event) if it was past the point
  when the finger lifted. A cancelled pan doesn't fire.

Children follow the pull through the same SharedValue, so whatever comes
in behind runs on the UI thread with the finger. A PHP write-back springs
a trigger axis as it does a snapping one. Only one-axis pans take a
trigger.

GestureAreaTriggerTest covers the Android side in the Robolectric module.

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