Skip to content

Conversation

@j-piasecki
Copy link
Member

Description

Ordering of touch events on the web was mostly aligned with Android. To unify the ordering across all platforms (along #3793), this PR changes it so that onTouchesDown is called before onBegin and onTouchesMove is called before onUpdate.

Another change is enforcing going through BEGAN when imperatively changing the state from UNDETERMINED to ACTIVE.

And a fix for an issue that came out due to the above changes - when the discrete gestures were imperatively activated inside onTouchesDown, the order was:

Touch down
Gesture begin
Gesture start
Touch cancel
Gesture end
Gesture finalize
Gesture begin
Gesture finalize

This was because those gestures transition to the END state immediately after ACTIVE, and get reset immediately. Then, the normal flow resumes, and they go to the BEGAN as a result of touch input. To prevent that, I changed cleanupFinishedHandlers to be queued as a microtask instead of being executed immediately. This should ensure that it will be called in the same run loop, but after the gesture handles its state.

Test plan

Tested on the following code:

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

export default function EmptyExample() {
  const pan = Gesture.Pan()
    .onTouchesDown((e, stateManager) => {
      'worklet';
      console.log('Touch down');
      stateManager.activate();
    })
    .onTouchesMove(() => {
      'worklet';
      console.log('Touch move');
    })
    .onTouchesUp(() => {
      'worklet';
      console.log('Touch up');
    })
    .onTouchesCancelled(() => {
      'worklet';
      console.log('Touch cancel');
    })
    .onBegin(() => {
      'worklet';
      console.log('Gesture begin');
    })
    .onStart((e) => {
      'worklet';
      console.log('Gesture start');
    })
    .onEnd(() => {
      'worklet';
      console.log('Gesture end');
    })
    .onFinalize(() => {
      'worklet';
      console.log('Gesture finalize');
    });

  return (
    <View style={styles.container}>
      <GestureDetector gesture={pan}>
        <View style={{ width: 300, height: 300, backgroundColor: 'green' }} />
      </GestureDetector>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

@j-piasecki j-piasecki requested a review from m-bert November 6, 2025 09:58
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.

2 participants