react-native-screens
react-native-screens copied to clipboard
While using `measureInWindow`, the `y` value is off
Description
Reposting issue reported here as asked: https://github.com/react-navigation/react-navigation/issues/12294
Given a useLayoutEffect that calls the measureInWindow of a ref , the y value is off. It seems to be off by the header height on iOS and web. For Android, I'm not sure what is off by exactly.
When the header is transparent or not shown, the y value from measureInWindow is correct for iOS and web but it is still off on Android.
// In a screen with default options
React.useLayoutEffect(() => {
triggerRef.current?.measureInWindow((x, y, width, height) => {
setTargetRect({ x, y, width, height });
});
}, [setTargetRect]);
// ...
<Pressable ref={triggerRef}
// ...
// This should place it right below the trigger
<View
style={{
// ...
position: "absolute",
top: targetRect.y + targetRect.height,
}}
// ...
Steps to reproduce
- Clone the minimal reproduction repo: https://github.com/mrzachnugent/react-navigation-measure-in-window-repro
- Run
npm install && npm run devto install the dependencies and start Expo Go in an iOS simulator. - Press the "Press here to open" button, the red square should appear right below the button.
- Try with web by pressing
win the terminal running metro - Try with android by pressing
ain the terminal running metro - Toggle to a transparent header by running
git checkout transparent-header, reload the apps and see the difference.
Snack or a link to a repository
https://github.com/mrzachnugent/react-navigation-measure-in-window-repro
Screens version
4.1.0
React Native version
0.76.3
Platforms
Android, iOS, Web
JavaScript runtime
Hermes
Workflow
Expo managed workflow
Architecture
Fabric (New Architecture)
Build type
None
Device
iOS simulator
Device model
No response
Acknowledgements
Yes
The same is also true for pageY in .measure() when measuring an element inside a native stack header. (You get a large negative number in iOS)
Having the same issue. y is always a large negative number. Has anyone found a workaround in the meantime?
Having the same issue. y is always a large negative number.
Hey, this is intended (and accurate) in case of items in header config, because the header is positioned above the screen, despite being its child in react element tree.
As for original issue - we're aware of it, however this won't be fixed any time soon. We have to do many hacky workarounds to make pressable work on new architecture and the values you get are result of these hacks.
Hi @kkafar , thanks for the response.
Does that mean that you suggest to use anything else but a Pressable for this (like a TouchableOpacity for example)?
In the React-Native docs, they suggest using a Pressable for a more "future proof" solution.
Does that mean that you suggest to use anything else but a Pressable for this (like a TouchableOpacity for example)?
@mrzachnugent I think I do not understand exactly what do you mean by "[...] for this".
The workarounds I've told you apply to any pressable/touchable component that is based on shadow state (i.e. any such component from react-native). These should however work just fine that's why we have our hacky solutions in place.
In case you experience some bugs related to pressables / touchables that are not existent w/o presence of react-native-screens please let me know - I'll be happy to engage in fixing them.
@kkafar Sorry, I don't think I understood the comment properly:
As for original issue - we're aware of it, however this won't be fixed any time soon. We have to do many hacky workarounds to make pressable work on new architecture and the values you get are result of these hacks.
I understood that the issue is with Pressable and the new architecture but what you are saying is that it is not just with Pressable, it's with every component based on the shadow tree, correct?
As for the "workarounds", I'm a little confused as I understood that it "won't be fixed any time soon" and I must of missed the suggested workaround.
Hey, this is intended (and accurate) in case of items in header config, because the header is positioned above the screen, despite being its child in react element tree.
Hey @kkafar thanks for the reply.
So I have custom dropdown in the headerRight section and I'm doing the following to position the dropdown below the trigger icon:
const toggleDropdown = () => {
if (isVisible) return;
triggerRef.current?.measureInWindow((x, y, width, height) => {
const screenWidth = Dimensions.get('window').width;
const rightPosition = screenWidth - (x + width); // Align dropdown's right edge with the trigger's right edge
setDropdownPosition({
y: y + height,
right: rightPosition,
});
setIsVisible(true);
});
};
This works perfectly fine with [email protected] & @react-navigation/[email protected] but it doesn't work anymore with [email protected] & @react-navigation/[email protected] using the new architecture.
If this large negative number for y now is intended, could you please explain how it is calculated and how I now need to calculate the y value for my dropdown?
Many thanks.