software-mansion / react-native-gesture-handler

Declarative API exposing platform native touch and gesture system to React Native.
https://docs.swmansion.com/react-native-gesture-handler/
MIT License
5.83k stars 952 forks source link

Cancel handlers by `NativeViewGestureHandler` #2788

Closed m-bert closed 1 month ago

m-bert commented 1 month ago

Description

This is a follow-up PR to #2787 that is meant to fix scrolling of swipeable elements. It overrides shouldHandlerBeCancelledBy method so that active NativeViewGestureHandler that is not a button, will cancel other handler.

Keep in mind that on web, if scroll has already started we cannot cancel it by calling preventDefault, hence it makes sense to cancel other handlers in that case (but we may want to limit it just to Pan).

Fixes #2617

Test plan

Tested on

import React from 'react';
import { View, Text } from 'react-native';
import { FlatList, GestureHandlerRootView } from 'react-native-gesture-handler';
import Swipeable from 'react-native-gesture-handler/Swipeable';

export default function Home() {
  type ItemProps = {
    item: {
      text: string;
    };
  };

  const data = Array.from({ length: 50 }, (_, i) => ({
    id: i,
    text: `Item ${i}`,
  }));

  const Item = ({ item }: ItemProps) => {
    return (
      <View style={{ margin: 10 }}>
        <Swipeable
          renderRightActions={() => (
            <View
              style={{
                justifyContent: 'center',
              }}>
              <Text style={{ color: 'white', textAlign: 'center' }}>
                Delete
              </Text>
            </View>
          )}>
          <View
            style={{
              height: 50,
              backgroundColor: 'white',
              justifyContent: 'center',
            }}>
            <Text>{item.text}</Text>
          </View>
        </Swipeable>
      </View>
    );
  };

  return (
    <GestureHandlerRootView>
      <FlatList
        data={data}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({ item }) => <Item item={item} />}
        style={{ maxHeight: 400 }}
      />
    </GestureHandlerRootView>
  );
}