Skip to content

Conversation

@akwasniewski
Copy link
Contributor

Description

This PR makes LogicDetector compatible with native gestures. Back in #3689 I decided to handle LogicDetector compatibility with native gestures for later, as it is a extremely niche feature and it seemed to require a lot of work. Turns out it doesn't, beacause we use wrap in LogicDetector we can handle them as normal gestures.

Test plan

Tested on:

import * as React from 'react';
import { StyleSheet, Text, View, ScrollView, Button } from 'react-native';
import {
  GestureHandlerRootView,
  NativeDetector,
  LogicDetector,
  useNative,
  useTap
} from 'react-native-gesture-handler';

export default function App() {
  const items = Array.from({ length: 100 }, (_, index) => `Item ${index + 1}`);
  const [enabled, setEnabled] = React.useState(true);
  const gesture = useNative({
    onStart: (e) => {
      'worklet';
      console.log('onStart');
    }
  });
  const outerGesture = useTap({
    onStart: (e) => {
      'worklet'
      console.log('onOuterStart');
    }
  });

  const SV1 = () => (
    <ScrollView style={styles.scrollView1}>
      {items.map((item, index) => (
        <View key={index} style={styles.item}>
          <Text style={styles.text}>{item}</Text>
        </View>
      ))}
    </ScrollView>
  );

  const SV2 = () => (
    <ScrollView style={styles.scrollView2}>
      {items.map((item, index) => (
        <View key={index} style={styles.item}>
          <Text style={styles.text}>{item}</Text>
        </View>
      ))}
    </ScrollView>
  );

  return (
    <GestureHandlerRootView style={styles.root}>
      <View style={styles.buttonContainer}>
        <Button
          title="Swap the child"
          onPress={() => setEnabled(!enabled)}
          color="#4a90e2"
        />
      </View>

      <NativeDetector gesture={outerGesture}>
        <View style={styles.outerContainer}>
          <View style={styles.frame}>
            <LogicDetector gesture={gesture}>
              {enabled ? <SV1 /> : <SV2 />}
            </LogicDetector>
          </View>
        </View>
      </NativeDetector>
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  scrollView1: {
    backgroundColor: 'pink',
    marginHorizontal: 20,
  },
  scrollView2: {
    backgroundColor: 'lightblue',
    marginHorizontal: 20,
  },

  item: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
    margin: 2,
    backgroundColor: 'white',
    borderRadius: 10,
  },
  text: {
    fontSize: 20,
    color: 'black',
  },
  root: {
    flex: 1,
    backgroundColor: '#fafafa',
    paddingTop: 60,
    alignItems: 'center',
  },
  buttonContainer: {
    marginBottom: 20,
    width: '80%',
  },
  outerContainer: {
    padding: 14,
    backgroundColor: '#fff',
    borderRadius: 18,
    borderWidth: 1,
    borderColor: '#e0e0e0',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.12,
    shadowRadius: 8,
    elevation: 5,
  },
  frame: {
    borderRadius: 14,
    borderWidth: 1,
    borderColor: '#d6d6d6',
    backgroundColor: '#fdfdfd',
    overflow: 'hidden',
  },
  innerContainer: {
    paddingVertical: 24,
    paddingHorizontal: 20,
    borderRadius: 12,
    alignItems: 'center',
    justifyContent: 'center',
  },
  active: {
    backgroundColor: '#e9f7ef',
    borderColor: '#4caf50',
    borderWidth: 1.5,
  },
  inactive: {
    backgroundColor: '#fff8e1',
    borderColor: '#ffb300',
    borderWidth: 1,
  },
});

@akwasniewski akwasniewski requested review from j-piasecki and m-bert and removed request for m-bert October 23, 2025 11:06
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious, why did the order of attach/detach change?

Copy link
Contributor Author

@akwasniewski akwasniewski Oct 27, 2025

Choose a reason for hiding this comment

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

If you follow the logic in updateLogicDetector closely you find out that if a specific handler was previously attached to another view, which was then detached (like in the example) - due to how handlers are stored - they would first be attached to the new view and then detached completely while looping through logicChildrenToDetach. I thought that it also happens in attachHandlers, but after careful testing it is not the case. I also fixed it on android today. For some reason I can't replicate it on web, I have to dig into that.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure what is updateLogicDetector.

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.

3 participants