Home > Enterprise >  React Native: How to properly disable touchable feedback when performing swiping gestures?
React Native: How to properly disable touchable feedback when performing swiping gestures?

Time:06-07

Swiping gestures i.e. scrolling, pull to refresh, etc.

I'm pulling my hair out trying to make this work, I don't understand how apps like Facebook accomplish this so well. It seems like such a simple thing to implement but I cannot for the life of me figure it out.

FYI: I'm using a FlatList with Touchable components inside. I've been messing around with the FlatList props (on scroll, on scroll begin drag, on scroll end drag, etc) as well as the Touchable props (on press, on press in, on press delay in, etc).

What I want: On the Facebook app, the MOMENT I begin scrolling or pulling to refresh, tap feedback is disabled so it doesn't look like I clicked on a post. But at the same time the MOMENT I tap on a post, the tap feedback is super responsive. How is this done?

What I get: The moment I begin scrolling or pulling to refresh, the tap feedback is played even though I wanted to scroll/refresh. To fix this, I tried putting a pressDelayIn of 50ms. But now, quickly tapping on a post doesn't play the feedback.

App.js

export default function App() {
  const [refreshing, setRefreshing] = useState(false);
  const [posts, setPosts] = useState([
    {
      id: 1,
      username: '@somedude',
      body: 'This is the best app ever, wow.',
    },
    {
      id: 2,
      username: '@doggo',
      body: 'Woof woof. Woof woof woof! Woof... Woof woof? Woof!',
    },
  ]);

  const onRefresh = () => {
    setRefreshing(true);
    setTimeout(() => setRefreshing(false), 1000);
  }

  return (
    <SafeAreaView style={styles.container}>
      <FlatList
        data={posts}
        renderItem={({ item }) => <Post post={item} />}
        keyExtractor={item => item.id}
        refreshing={refreshing}
        onRefresh={onRefresh}
      />
    </SafeAreaView>
  );
}

Post.js

export const Post = ({ post }) => {
  return (
  <TouchableOpacity
    activeOpacity={0.5}
    onPress={() => console.log(`Press id ${post.id}`)}
  >
    <View style={styles.postPontainer}>
      <View style={{ marginBottom: 5 }}>
        <Text>{post.username}</Text>
      </View>
      <View style={styles.textContainer}>
        <Text>{post.body}</Text>
      </View>
    </View>
  </TouchableOpacity>
  );
}

CodePudding user response:

you can check this answer i think it will help you to resolve your problem.

I think pointerEvents is the property you need to handle this. this property controls whether the View can be the target of touch events.

https://stackoverflow.com/a/47890427/14221660

https://stackoverflow.com/a/39720112/14221660

CodePudding user response:

I definitely understand the frustration. I'd 1 ucup's suggestion to checkout react-native-gesture-handler. In the mean time, I disabled the TouchableOpacity while scrolling, and dialed back the delayPressIn and it seem to work pretty well. See what you think:

Add state to track canPress

export default function App() {
  const [canPress, setCanPress] = useState(true); //
  const [refreshing, setRefreshing] = useState(false);
  ...

Wire up to the FlatList

<SafeAreaView style={styles.container}>
    <FlatList
      data={posts}
      onScrollBeginDrag={() => setCanPress(false)} //
      onScrollEndDrag={() => setCanPress(true)} //
      renderItem={({item}) => <Post post={item} canPress={canPress} />} //
      keyExtractor={item => item.id}
      refreshing={refreshing}
      onRefresh={onRefresh}
    />
</SafeAreaView>

Then just wire up to your TouchableOpacity

<TouchableOpacity
      disabled={!canPress} //
      activeOpacity={0.5}
      delayPressIn={50} //
      onPress={() => console.log(`Press id ${post.id}`)}>
      ...

Good luck!

  • Related