Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onPress is not called after using useNativeDriver transform button #36504

Closed
ThinkerLu opened this issue Mar 16, 2023 · 22 comments · May be fixed by #44447
Closed

onPress is not called after using useNativeDriver transform button #36504

ThinkerLu opened this issue Mar 16, 2023 · 22 comments · May be fixed by #44447
Labels
Component: Button Resolution: Fixed A PR that fixes this issue has been merged. Type: New Architecture Issues and PRs related to new architecture (Fabric/Turbo Modules)

Comments

@ThinkerLu
Copy link

ThinkerLu commented Mar 16, 2023

Description

After using useNativeDriver transform button, finger movement occurs when the button is pressed, the button's onPress will not be called, but the visual feedback of the button is normal.
The bug only occurs on Android devices, and when the new architecture is enabled, useNativeDriver=true is set.

React Native Version

0.71.4

Output of npx react-native info

System:
OS: macOS 13.1
CPU: (10) arm64 Apple M1 Pro
Memory: 148.16 MB / 16.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 19.7.0 - /opt/homebrew/bin/node
Yarn: 1.22.19 - /opt/homebrew/bin/yarn
npm: 9.5.0 - /opt/homebrew/bin/npm
Watchman: 2023.03.06.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: Not Found
SDKs:
iOS SDK:
Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1
Android SDK:
API Levels: 28, 29, 30, 31, 32, 33
Build Tools: 28.0.3, 30.0.2, 30.0.3, 31.0.0, 33.0.0
System Images: android-31 | Google APIs ARM 64 v8a, android-33 | Google APIs ARM 64 v8a
Android NDK: Not Found
IDEs:
Android Studio: Electric Eel 2022.1.1 Patch 2 Electric Eel 2022.1.1 Patch 2
Xcode: 14.2/14C18 - /usr/bin/xcodebuild
Languages:
Java: 11.0.15 - /opt/homebrew/opt/openjdk@11/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: 18.2.0 => 18.2.0
react-native: 0.71.4 => 0.71.4
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found

Steps to reproduce

Run my code, Press the button after scrolling the FlatList, move your finger slightly and lift it up.

Snack, code example, screenshot, or link to a repository

import React, {useRef, useState} from 'react';
import {View, Text, Button, Animated} from 'react-native';

const componentList: number[] = Array.from(new Array(100).keys());

const App = () => {
const currScroll = useRef(new Animated.Value(0)).current;
const [count, setCount] = useState(0);

return (
<View style={{flex: 1}}>
<Animated.View
style={{
position: 'absolute',
zIndex: 2,
width: '100%',
transform: [{translateY: currScroll}],
}}>
<Button
title={Press count : ${count}}
onPress={() => {
console.log('pressed');
setCount(count + 1);
}}>
</Animated.View>
<Animated.FlatList
style={{width: '100%', height: '100%', position: 'absolute', zIndex: 1}}
data={componentList}
renderItem={({index}) => (
<Text
style={{
backgroundColor: 'white',
height: 28,
}}>
{index}

)}
keyExtractor={item => item.toString()}
onScroll={Animated.event(
[
{
nativeEvent: {
contentOffset: {
y: currScroll,
},
},
},
],
{useNativeDriver: true},
)}></Animated.FlatList>

);
};

export default App;

@ThinkerLu ThinkerLu added Needs: Triage 🔍 Type: New Architecture Issues and PRs related to new architecture (Fabric/Turbo Modules) labels Mar 16, 2023
@iMonk777
Copy link

iMonk777 commented May 5, 2023

Hi @ThinkerLu , we still have this issue. Did you find any solution for this?

@jugshaurya
Copy link

jugshaurya commented May 29, 2023

+1, after applying transform: translateX/Y/Z(*), on Animated.View, internal content of this View become non-responsive, works after multiple clicking.

It comes after using New Arch.Even used latest 0.72.0-RC.3

Tested Today: 29/05/23

@skinsapp
Copy link

skinsapp commented Jun 11, 2023

@jugshaurya I can confirm I'm having the same issue, using 71.10, android. It basically makes the new architecture unusable on Android, unless you plan to have no animation. It's occurring with all touchables and pressables.

related: #36710

@jugshaurya
Copy link

jugshaurya commented Jun 11, 2023

@jugshaurya I can confirm I'm having the same issue, using 71.10, android. It basically makes the new architecture unusable on Android, unless you plan to have no animation. It's occurring with all touchables and pressables.

related: #36710

I found a temp/possible solution for it, after researching for more than 2 weeks.

Use onPressIn instead of onPress !

Let me know if it also works for you. Also to increase tappable area to make button more responsive, you can use hitslop prop.

@vrgimael
Copy link

@jugshaurya I can confirm I'm having the same issue, using 71.10, android. It basically makes the new architecture unusable on Android, unless you plan to have no animation. It's occurring with all touchables and pressables.
related: #36710

I found a temp/possible solution for it, after researching for more than 2 weeks.

Use onPressIn instead of onPress !

Let me know if it also works for you. Also to increase tappable area to make button more responsive, you can use hitslop prop.

This is not a solution as it triggers accidentally on any scrollable item

@jugshaurya
Copy link

@jugshaurya I can confirm I'm having the same issue, using 71.10, android. It basically makes the new architecture unusable on Android, unless you plan to have no animation. It's occurring with all touchables and pressables.
related: #36710

I found a temp/possible solution for it, after researching for more than 2 weeks.

Use onPressIn instead of onPress !

Let me know if it also works for you. Also to increase tappable area to make button more responsive, you can use hitslop prop.

This is not a solution as it triggers accidentally on any scrollable item

Can you share an example gif or something to get the better context, because i used this solution for codebase, it is working fine.

Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 26, 2023
Copy link

github-actions bot commented Jan 2, 2024

This issue was closed because it has been stalled for 7 days with no activity.

@github-actions github-actions bot closed this as completed Jan 2, 2024
@sammy-SC sammy-SC reopened this Jan 6, 2024
@github-actions github-actions bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Jan 7, 2024
@cipolleschi
Copy link
Contributor

Hi everyone, we have this investigation marked as high priority, so we hopefully would be able to make progress on this as fast as we can.

To help us out, we would greatly appreciate a reproducer starting from this repo. I understand that the issue does not reproduce consistently, but if you can set up something and tell us how and how much we need to interact with the repro to get the issue happening, this will help us a lot.

Thank you all for the cooperation! 🙏

@sonicbaume
Copy link

@cipolleschi Here's the example from @ThinkerLu as a reproducer repo, and a video of the result.

Reproducer: https://github.com/sonicbaume/fabric-onpress-bug-reproducer

Video:

onpress-example.mp4

@sonicbaume
Copy link

@cipolleschi Is this still considered high priority? Is there anything else you need?

@cortinico
Copy link
Contributor

@cipolleschi Is this still considered high priority? Is there anything else you need?

Yes it is. If someone is willing to attempt to fix it and send a PR, it would be greatly appreaciated. Otherwise we'll eventually fix it in the (hopefully soon) future

@cipolleschi
Copy link
Contributor

Thanks for your patience, competing priorities took most of my time. :(

As @cortinico said, we want to fix this issue, together with some other that are affecting the New Architecture. Bear with us, we will get there.

@cipolleschi
Copy link
Contributor

cipolleschi commented May 31, 2024

Hi @sonicbaume @ThinkerLu @iMonk777 @jugshaurya @vrgimael, sorry that this took us so long.

I was trying the reproducer and it feels like it is fixed on 0.74.1 with regular touches.

There is still something weird related to when you tap-drag-release within the button. It looks that onPress is not invoked in that case. It works if you click-drat to the top-release: it looks like that when we 'release' the touch, we are not considering the translated position.

nativeDriver.mov

Let's note that this behavior happens also on iOS:

Screen.Recording.2024-05-31.at.15.52.51.mov

cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 11, 2024
Summary:
## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 11, 2024
Summary:
## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 11, 2024
Summary:
## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 12, 2024
Summary:
## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 12, 2024
Summary:
## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 15, 2024
…#45413)

Summary:
Pull Request resolved: facebook#45413

## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Reviewed By: sammy-SC

Differential Revision: D58182480
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 15, 2024
…#45413)

Summary:
Pull Request resolved: facebook#45413

## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480

Reviewed By: sammy-SC
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 15, 2024
…#45413)

Summary:
Pull Request resolved: facebook#45413

## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Reviewed By: sammy-SC

Differential Revision: D58182480
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 16, 2024
…#45413)

Summary:
Pull Request resolved: facebook#45413

## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480

Reviewed By: sammy-SC
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 16, 2024
…#45413)

Summary:
Pull Request resolved: facebook#45413

## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480

Reviewed By: sammy-SC
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 16, 2024
…#45413)

Summary:
Pull Request resolved: facebook#45413

## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480

Reviewed By: sammy-SC
cipolleschi added a commit to cipolleschi/react-native that referenced this issue Jul 16, 2024
…#45413)

Summary:
Pull Request resolved: facebook#45413

## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [facebook#36504](facebook#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Differential Revision: D58182480

Reviewed By: sammy-SC
facebook-github-bot pushed a commit that referenced this issue Jul 16, 2024
Summary:
Pull Request resolved: #45413

## Changes
Add an example in RNTester to test that pressability with NativeDrivers works properly.

## Context
The pressability handling is a bit peculiar.
We have to handle 3 main behaviors:
* `PressIn` -> `PressOut` => triggers the `onPress`
* `PressIn` -> move inside the rectangle -> `PressOut` => triggers the `onPress`
* `PressIn` -> move outside the rectangle -> `PressOut` => cancel `onPress`.

For the first case, we detect whether the press happens inside a component in the Native layer only. And everything works.

When a move is involved, we:
1. Detect the initial press in the Native layer
2. We move the coursor and we delegate the detection of whether we are inside of a rect or not to the JS layer
3. The JS layer asks the C++ layer about the layout and decide whether we are in case 2 (move but still inside the rect) or in case 3 (move but outside the rect).

The problem is that with `nativeDriver` and animations, the C++ layer doesn't know about where the receiver view actually is.
This results in issues like the one shown by [#36504](#36504), where the onMove is not handled correctly.

## Solution
The solution is to keep detecting whether we are in the receiver view or not in the Native layer and pass the receiver view position and size back to JS so that the JS layer don't have to jump to C++ to make this decision.

We decided to pass the frame information because the JS layer is adding some padding and configurations to the final rectangle and we don't want to lose those configurations.

## Changelog
[General][Added] - Add example in RNTester to show that pressability works properly with NativeDrivers

Reviewed By: sammy-SC

Differential Revision: D58182480

fbshipit-source-id: 9ca4fb9a3ca1a8af52ccbe208cbfe8434175f87d
@cipolleschi
Copy link
Contributor

This will be fixes in 0.76.

@cortinico cortinico added Resolution: Fixed A PR that fixes this issue has been merged. and removed Needs: Triage 🔍 labels Sep 23, 2024
@61xin
Copy link

61xin commented Oct 28, 2024

This will be fixes in 0.76.

Hi @cipolleschi, what is the commit id that fixed this bug? Will the fixes be synced to previous versions, such as 0.75?

@cipolleschi
Copy link
Contributor

@61xin there are multiple commits required to fix this issue. It will be quite hard to backport the fix to previous versions, plus the New Architecture is considered stable and ready for production in 0.76.
So I strongly suggest to update to 0.76 if you want to migrate to the New Architecture, also because that version will contains many more fixes for the New Arch.

@61xin
Copy link

61xin commented Oct 29, 2024

@61xin there are multiple commits required to fix this issue. It will be quite hard to backport the fix to previous versions, plus the New Architecture is considered stable and ready for production in 0.76. So I strongly suggest to update to 0.76 if you want to migrate to the New Architecture, also because that version will contains many more fixes for the New Arch.

ok,thank you!

@fdecampredon
Copy link

@61xin After upgrading to 0.76.1 I can say that the issue is still present

@cipolleschi
Copy link
Contributor

@fdecampredon can you share a reproducer? We have a screen in RNTester to test this case and I'm sure it was fixed. Maybe we missed some edge case.

@fdecampredon
Copy link

@cipolleschi I'm really sorry after more investigation I think it is more related to this one : #44768.
We'll try to make a minimal reproduction example but it's a bit hard since the problem is deeply nested in a very complex screen.

@ZhangBinglei2015
Copy link

I am using react native 0.72 and this solve my problem,you can try it!

import type {ViewProps} from 'react-native'
import {PanResponder, View} from 'react-native'

export type TouchComponentProps = {
  onPress: () => void
}

export default (props: ViewProps & TouchComponentProps) => {
  const panresponder = PanResponder.create({
    onStartShouldSetPanResponder: () => true,
    onShouldBlockNativeResponder: () => false,
    onPanResponderRelease: () => {
      props.onPress()
    },
  })

  return (
    <View {...props} {...panresponder.panHandlers}>
      {props.children}
    </View>
  )
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Button Resolution: Fixed A PR that fixes this issue has been merged. Type: New Architecture Issues and PRs related to new architecture (Fabric/Turbo Modules)
Projects
None yet
Development

Successfully merging a pull request may close this issue.