Coder Social home page Coder Social logo

Comments (30)

tcloudAce avatar tcloudAce commented on September 27, 2024 4

same issue !! onPressIn and onPressOut is work, but onPress not work only!

from react-native.

copiri-six avatar copiri-six commented on September 27, 2024 2

Just chiming in to say that we have been struggling with this as well. Both this issue and #36710 describe our problem quite well, although #36710 got hijacked and closed based on an unrelated bug being addressed (the solved bug had to do with the new architecture, while the OP stated his problem existed before the new architecture was even created).

Looking forward to any movement on this issue, because its random nature makes it effectively impossible to reliably reproduce.

from react-native.

gtwilliams03 avatar gtwilliams03 commented on September 27, 2024 2

@tcloudAce Thank you - however this issue is pretty much with anything pressable (not just a button). Buttons, navigation tabs, etc. I should also add that the app responds to presses for a very short period of time (<3 seconds) and then ceases responding to any taps anywhere on the Android device screen. The emulators work fine so this is very difficult to reproduce/test.

from react-native.

tcloudAce avatar tcloudAce commented on September 27, 2024 1

In my scenario, I can reproduce this error 100% of the time (onPress does not respond, but interestingly, the animation effect of TouchableOpacity still shows). I have tested it with Expo 51, Expo 50, React Native 0.74.1, and React Native 0.73.6. The test environment includes Samsung S23 and S24. In a real device environment, even onPressIn and onPressOut do not work, whereas on the emulator, onPressIn and onPressOut respond normally, but onPress does not respond.

My scenario is similar to a step-by-step installation guide Page, which is built with a ScrollView in RN. There are about 7 pages within the ScrollView. If a Modal is opened within these pages, the onPress of buttons inside the Modal does not respond. Currently, I have disabled react-native-screens and used onPressOut instead of onPress. Although it works, it causes accidental clicks when scrolling (due to onPressOut).

Additionally, to add more context, my ScrollView contains nested ScrollViews. In this environment, onPress 100% fails to respond. The issue does not occur with non-nested ScrollViews.

from react-native.

gtwilliams03 avatar gtwilliams03 commented on September 27, 2024 1

I have the same issue with our app. iOS and Android emulator work fine. iOS production app works fine. Recently though, the Android production app has become relatively unusable. You can log in and within a few seconds, pretty much every pressable item becomes unresponsive.

from react-native.

cortinico avatar cortinico commented on September 27, 2024

Will add, if needed

Can we get a reproducer? As otherwise it's extremely hard to debug this issue.

from react-native.

DrZoidberg09 avatar DrZoidberg09 commented on September 27, 2024

Yes, will follow later today.

from react-native.

cortinico avatar cortinico commented on September 27, 2024

Yes, will follow later today.

Any news on this?

from react-native.

github-actions avatar github-actions commented on September 27, 2024
⚠ī¸ Missing Reproducible Example
ℹī¸ We could not detect a reproducible example in your issue report. Please provide either:

from react-native.

DrZoidberg09 avatar DrZoidberg09 commented on September 27, 2024

I edited the original post. This is the repro: https://github.com/DrZoidberg09/RN-Android-Touch-Issue/

from react-native.

DrZoidberg09 avatar DrZoidberg09 commented on September 27, 2024

@cortinico Anything else you need from me to look into this?

from react-native.

imransilvake avatar imransilvake commented on September 27, 2024

on Samsung devices onPress doesn't work. All customers with Samsung devices (S23, S24) are reporting it. any solution to make it work?

from react-native.

tcloudAce avatar tcloudAce commented on September 27, 2024

@imransilvake @DrZoidberg09 Using react-native-handler-gesture to build a button can temporarily solve this problem. Here is the sample code:
import React from "react";
import { TapGestureHandler, State } from "react-native-gesture-handler";
import { View } from "react-native";

export default function Pressable({ onPress, children, style, disabled }) {
const onHandlerStateChange = (event) => {
if (event.nativeEvent.state === State.END) {
onPress();
}
};

return (

{children}

);
}

from react-native.

tcloudAce avatar tcloudAce commented on September 27, 2024

@cortinico In my scenario, the TextInput also cannot be focused. This is indeed a peculiar issue.

from react-native.

tcloudAce avatar tcloudAce commented on September 27, 2024

@gtwilliams03 If the buttons are not working, you can try the following code:
`import React from "react";
import { TapGestureHandler, State } from "react-native-gesture-handler";
import { View } from "react-native";

export default function Pressable({ onPress, children, style, disabled }) {
const onHandlerStateChange = (event) => {
if (event.nativeEvent.state === State.END) {
onPress();
}
};

return (

{children}

);
}`

from react-native.

tcloudAce avatar tcloudAce commented on September 27, 2024

In my case, changing the component layout and applying the above code temporarily solved my problem. The only thing that is certain is that iOS and Android often cannot use the same layout. Code that runs successfully and without issues on Android usually works on iOS, but not the other way around. Moreover, this issue is not only present in the latest versions of React Native but has existed in many past versions as well. I hope this helps everyone.

from react-native.

cortinico avatar cortinico commented on September 27, 2024

DrZoidberg09/RN-Android-Touch-Issue

Can we get a non-expo reproducer using this template instead:
https://github.com/react-native-community/reproducer-react-native

The provided repro is quite involved (uses expo router) and I'd like to isolate this issue as much as possible.

from react-native.

DrZoidberg09 avatar DrZoidberg09 commented on September 27, 2024

Tried to reproduce it with pure RN and the repo you shared. So far, I could not reproduce it. Even with the RN-Navigation header issue shown in the other Expo based repro.

So far, it seems it's neither react-native nor react-navigation, but Expo(-router).

But I will keep trying to reproduce it in the next days.

from react-native.

cortinico avatar cortinico commented on September 27, 2024

So far, it seems it's neither react-native nor react-navigation, but Expo(-router).

That's sometimes related to react-native-screens (at least it was in the past). Worth a try with -screens to see if it reproduces there

from react-native.

DrZoidberg09 avatar DrZoidberg09 commented on September 27, 2024

I have react-native-screens and react-navigation stack also running in the repro. Here it works fine. In the main project with Expo it is not.

Another weird behavior:

If I run Expo development build on the native device most is working pretty ok besides onPress in the header bar. (onPressOut and In is working nicely though). However, if I build a proper apk and run it on the native (Samsung) device. Everything pressable in a stack is not working, incl. every list, button, etc. (Also the positioning of position absolute items is different if I use development build or an apk on the same device...)

from react-native.

DrZoidberg09 avatar DrZoidberg09 commented on September 27, 2024

This seems to be very close to the issue as well: software-mansion/react-native-screens#2150

from react-native.

DrZoidberg09 avatar DrZoidberg09 commented on September 27, 2024

@cortinico I could track it down to expo-router. Please look at the github repo. I added a reproducer for each: pure RN, expo with router and expo without router.

The two repos without router work. With router it does not.

from react-native.

cortinico avatar cortinico commented on September 27, 2024

The two repos without router work. With router it does not.

Great so let's close it for now and move the conversation over to: expo/expo#30032

from react-native.

tremblerz avatar tremblerz commented on September 27, 2024

I was encountering a similar issue -- TouchableOpacity (and other wrappers of Pressable) not working on Android but working fine in iOS. However, I was able to fix the issue by adding a zIndex: 10 in the style property. 10 is just a number here, basically it had to be on the top.

from react-native.

littleski avatar littleski commented on September 27, 2024

I have done a little digging into Pressability.js
It seems that the condition to fire onPress is: isPressInSignal(prevState) && signal === 'RESPONDER_RELEASE'
and then that !isPressCanceledByLongPress

In my testings of this wonky behaviour.

  • Sometimes, the events are in the right order (it's rare, but it is happening). (i get RESPONDER_ACTIVE_PRESS_IN as prevState)
  • Sometime not at all, and when i get the RESPONDER_RELEASE signal, the prevState is RESPONDER_ACTIVE_PRESS_OUT and so onPress do not fire.
const isPressInSignal = (signal: TouchState) =>
  signal === 'RESPONDER_INACTIVE_PRESS_IN' ||
  signal === 'RESPONDER_ACTIVE_PRESS_IN' ||
  signal === 'RESPONDER_ACTIVE_LONG_PRESS_IN';

onPressIn and onPressOut are not using the same State machine conditions, and thus, are not impacted by the issue.

Haven't fixed (as adding the prev event to the function is surely not what is supposed to happen), and i am trying to understand a bit more to not do shit, but maybe it can help someone understand more the issue.

from react-native.

DominikHinc avatar DominikHinc commented on September 27, 2024

I investigated it a little more and from what I see this is a case of measure not synchronizing correctly with the coordinates of touches.

On Android with new architecture the touches will be returned as coordinates relative to the root view. So if the screen you are using is 300 x 700 pixels, it will fall somewhere between that.

The Pressablity.js file, mentioned by @littleski then takes those touch coordinates and compares them to the coordinates of the responder (returned by the measure function),

 _measureResponderRegion(): void {
    if (this._responderID == null) {
      return;
    }

    if (typeof this._responderID === 'number') {
      UIManager.measure(this._responderID, this._measureCallback);
    } else {
      this._responderID.measure(this._measureCallback);
    }
  }
  _measureCallback = (
    left: number,
    top: number,
    width: number,
    height: number,
    pageX: number,
    pageY: number,
  ) => {
    if (!left && !top && !width && !height && !pageX && !pageY) {
      return;
    }
    this._responderRegion = { // <------ position of the responder relative to the root view (this is the problematic place, which is explained below
      bottom: pageY + height,
      left: pageX,
      right: pageX + width,
      top: pageY,
    };
  };

BUT ONLY on the responder move:

 onResponderMove: (event: PressEvent): void => {
        /* ... */
        const touch = getTouchFromPressEvent(event); // <--- coordinates of users touch
        /* ... */
        if (this._isTouchWithinResponderRegion(touch, responderRegion)) {
          this._receiveSignal('ENTER_PRESS_RECT', event);
        } else {
          this._cancelLongPressDelayTimeout();
          this._receiveSignal('LEAVE_PRESS_RECT', event);
        }
      },

  _isTouchWithinResponderRegion(
    touch: $PropertyType<PressEvent, 'nativeEvent'>,
    responderRegion: $ReadOnly<{|
      bottom: number,
      left: number,
      right: number,
      top: number,
    |}>,
  ): boolean {
   /* ... */
    return (
      touch.pageX > regionLeft &&
      touch.pageX < regionRight &&
      touch.pageY > regionTop &&
      touch.pageY < regionBottom
    );
  }

And that is why this issue only appears on some android devices which are more sensitive. Emulators and less sensitive devices will never trigger the onResponderMove callback. I found out that this issue can be reproduced on emulators just by moving the mouse a little bit during a touch.

As for the reason why this bug even occurs at all, it comes down to the data returned from the measure. The pageX and pageY in some special circumstances will return coordinates far exceeding the boundaries of the screen. From what I tested for now, this is a case for both react-native-tab-view and react-native-pager-view. I haven't found a time to look into them, what exact construct is causing that, but I know for sure that the responder pageX and pageY is being offset there by the amount of the travel distance it had to do before appearing on the screen.
Let's take tab-view for example:
If we have 3 tabs in tab-view , each screen-wide with it's own touchable button (responder), the responder coordinates for the first tab button will be normal - it will respond to touches correctly, but for the second and third tab the coordinates will be offset (pageX) by respectively (in case of 300 pixel wide screen) - 300 pixels and 600 pixels, meaning that as soon as the responder calls onResponderMove the touch will be broken (put into LEAVE_PRESS_RECT state) which it then has no way of fixing, since the X position of the touch will be like 112 pixels and the responder X will be 412 pixels (out of screen).

For now I don't know how to fix it.

from react-native.

DominikHinc avatar DominikHinc commented on September 27, 2024

It's definitely a react-native-pager-view issue, since tab-view also relies on that, for now I simply swapped all the buttons in the app with this component

const ManuallyHandledButton = ({ onPress, children, ...props }) => {
  const _touchActivatePositionRef = useRef(null)

  const _onPressIn = useCallback((e) => {
    const { pageX, pageY } = e.nativeEvent

    _touchActivatePositionRef.current = {
      pageX,
      pageY
    }
  }, [])

  const _onPress = useCallback(
    (e) => {
      const { pageX, pageY } = e.nativeEvent

      const absX = Math.abs(_touchActivatePositionRef.current.pageX - pageX)
      const absY = Math.abs(_touchActivatePositionRef.current.pageY - pageY)

      const dragged = absX > PRECISION || absY > PRECISION

      if (!dragged) {
        onPress?.(e)
      }
    },
    [onPress]
  )

  return (
    <Pressable
      onResponderStart={_onPressIn}
      onResponderEnd={_onPress}
      {...props}
    >
      {children}
    </Pressable>
  )
}


const PressableForwarder =
  global?.nativeFabricUIManager && IS_ANDROID
    ? ManuallyHandledButton
    : TouchableOpacity

export default PressableForwarder

And it seems to work good enough

from react-native.

littleski avatar littleski commented on September 27, 2024

Pigging backing on @DominikHinc

UiManager

const UIManager: UIManagerJSInterface = {
  ...UIManagerImpl,
  measure(
    reactTag: number,
    callback: (
      left: number,
      top: number,
      width: number,
      height: number,
      pageX: number,
      pageY: number,
    ) => void,
  ): void {
    if (isFabricReactTag(reactTag)) {
      const FabricUIManager = nullthrows(getFabricUIManager());
      const shadowNode =
        FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
      if (shadowNode) {
        FabricUIManager.measure(shadowNode, callback);
      } else {
        console.warn(`measure cannot find view with tag #${reactTag}`);
        // $FlowFixMe[incompatible-call]
        callback();
      }
    } else {
      // Paper
      UIManagerImpl.measure(reactTag, callback);
    }
  },

So here is the difference between new arch and old which seems logic. need to dig a bit in the Java to understand the difference and what may have been broken in the new arch java binding.

from react-native.

DominikHinc avatar DominikHinc commented on September 27, 2024

@littleski turns out all I had to do was to implement this callstack/react-native-pager-view#836

from react-native.

littleski avatar littleski commented on September 27, 2024

The repro doesn't use this. It's more than likely that this is just a workaround for one lib. I don't use this package either. Might help understand the issue tho.

from react-native.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤ī¸ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.