-
Notifications
You must be signed in to change notification settings - Fork 24.3k
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
useWindowDimensions() returns swapped height and width in iOS #29290
Comments
Is it that useWindowDimensions is returning the wrong numbers, or is the component not rerendering in response to the changes in orientation? Have you validated that it's running (with a log statement or whatever) and reporting the wrong numbers? |
@chrisglein Android is working fine. iOS is behaving strangely, not a simple unresponsive but kind of a “delayed” state.
Since step 3 the behaviour repeats, only by re-launching the app could you reproduce step 1 and 2. |
Adding to the context, the above behavior is also confirmed with console logs. |
This is problem too. The solution i did was to listen to view onlayoutevent to get the right width and height(which you store on state) For orientation, i used react native locker and do Orientatio.addListener and store the result in state too. Yeah unfortunately handling those is sometimes feels too manual |
Only workaround is to work with custom native modules. Even |
I also noticed that the sizes are swapped for a very short amount of time when the iPad is unlocked and the app was still active. Though, I am not dealing with with Dimensions directly but instead have a root view that has an import React, { useCallback } from 'react'
import { LayoutChangeEvent, StyleSheet, View } from 'react-native'
import { useDebouncedCallback } from '../../../hooks'
const styles = StyleSheet.create({
container: {
flex: 1,
},
})
let i = 0
const MeasureView: React.FC = (props) => {
const { children } = props
// Create handlers
const [setDimensions] = useDebouncedCallback(
(width: number, height: number) => {
alert('setDimensions ' + i + ': width=' + width)
i++
},
500
)
const handleLayout = useCallback(
(event: LayoutChangeEvent) => {
const { width, height } = event.nativeEvent.layout
alert('handleLayout ' + i + ': width=' + width)
i++
setDimensions(width, height)
},
[setDimensions]
)
return (
<View style={styles.container} onLayout={handleLayout}>
{children}
</View>
)
}
export default MeasureView The output is:
|
@jaulz your issue may not be the same as this one, but the snippet could be a workaround of mine though! |
@vicary in fact this was my approach as a workaround but as you can see it doesn't solve the dimensions issue but just uses a debounce to avoid it. The original issue that dimensions are swapped is still a problem. |
I'm seeing similar problems on Android, except that after the 1st rotation, the values seem to be stuck on whatever the 2nd state was (e.g. if I started in portrait mode, after I rotate to landscape the |
I am curious on how Facebook addresses this kind of issues, is it supposed to be fixed by the community via PR or shall we wait? |
I only have this issue with Android. If device is in portrait and I rotate it to landscape and quickly back to portrait the width and height numbers returns swap. This hurts my layout as my layout depends on these numbers |
Android landscape, fullscreen without system's Status Bar or Navigation Bar.
|
#34014) Summary: This fix solves a problem very well evaluated [here](Expensify/App#2727) as well as this [one](#29290). The issue is that when the app goes to background, in landscape mode, the RCTDeviceInfo code triggers an orientation change event that did not physically happen. Due to that, we get swapped values returned when going back to the app. I debugged the react-native code, and to me it seems that react native publishes the orientation change event one extra time when switching the state of the app to 'inactive'. Here is what is happening: 1. iPad is in landscape. 2. We move the app to inactive state. 3. Native Code queues portrait orientation change (no such change happened physically), and immediately after it triggers landscape change (same as we had in point 1). 4. We restore the app to active state. 5. The app receives two queued orientation change events, one after another. 6. The quick transition between portrait and landscape happens even though it never went back to portrait. Fresh `react-native init` app repro case can be found here: https://github.com/lbaldy/issue-34014-repro Video presenting the issue (recorded while working on: Expensify/App#2727 ): https://www.youtube.com/watch?v=nFDOml9M8w4 ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - Fix the way the orientation events are published, to avoid false publish on orientation change when app changes state to inactive Pull Request resolved: #34014 Test Plan: ### Test Preparation 1. Make sure you have a working version of E/App. 2. Open App/src/components/withWindowDimensions.js and update the constructor by changing this line: `this.onDimensionChange = _.debounce(this.onDimensionChange.bind(this), 100);` to `this.onDimensionChange = this.onDimensionChange.bind(this);` 3. Open the NewExpensify.xcodeproj in xCode. 4. Open the RCTDeviceInfo.mm file and replace it's contents with the file from this PR. 5. Select your device of choice (I suggest starting with iPad mini) and run the app though xCode. 6. From this point you can move to the test scenarios described below. ### iPad Mini tests: Reproduction + Fix test video (Test 1): https://youtu.be/jyzoNHLYHPo Reproduction + Fix test video (Test 2): https://youtu.be/CLimE-Fba-g **Test 1:** 1. Launch app in portrait, open chat - no sidebar visible. 7. Switch to landscape - sidebar shows. 8. Put app to background. 9. Put app back to foreground - make sure the side menu doesn't flicker. **Test 2:** 1. Launch app in portrait, open chat - no sidebar visible. 2. Switch to landscape - sidebar shows. 3. Put app to background. Switch orientation back to portrait. 4. Put app back to foreground - make sure the side menu hides again as it should be in portrait. ### iPad Pro tests: Reproduction + Fix test video (Test 3, Test 4): https://youtu.be/EJkUUQCiLRg iPad mini test 1 applies. Scenario 2 does not as the screen is too wide in both orientations and iPad pro shows sidebar always. **Test 3:** 1. launch the app. 2. Make sure you're in landscape mode. 3. See split screen with some other app. Make sure the side bar is visible. 4. Play with the size of the view, resize it a bit. When the view shrinks it should hide the sidebar, when it grows it should show it. 10. Move the app to background and back to foreground, please observe there are no flickers. **Test 4:** 1. Launch the app. 2. Make sure you're in landscape mode. 3. Make the multitasking view and make Expensify app a slide over app. 4. Move back to fullscreen/split screen. Make sure the menu is shown accordingly 5. Move the app to background and back to foreground, please observe there are no flickers. ### iPhone: Non reg with and without the fix video: https://youtu.be/kuv9in8vtbk Please perform standard smoke tests on transformation changes. Reviewed By: cipolleschi Differential Revision: D37239891 Pulled By: jacdebug fbshipit-source-id: e6090153820e921dcfb0d823e0377abd25225bdf
#34014) Summary: This fix solves a problem very well evaluated [here](Expensify/App#2727) as well as this [one](#29290). The issue is that when the app goes to background, in landscape mode, the RCTDeviceInfo code triggers an orientation change event that did not physically happen. Due to that, we get swapped values returned when going back to the app. I debugged the react-native code, and to me it seems that react native publishes the orientation change event one extra time when switching the state of the app to 'inactive'. Here is what is happening: 1. iPad is in landscape. 2. We move the app to inactive state. 3. Native Code queues portrait orientation change (no such change happened physically), and immediately after it triggers landscape change (same as we had in point 1). 4. We restore the app to active state. 5. The app receives two queued orientation change events, one after another. 6. The quick transition between portrait and landscape happens even though it never went back to portrait. Fresh `react-native init` app repro case can be found here: https://github.com/lbaldy/issue-34014-repro Video presenting the issue (recorded while working on: Expensify/App#2727 ): https://www.youtube.com/watch?v=nFDOml9M8w4 ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - Fix the way the orientation events are published, to avoid false publish on orientation change when app changes state to inactive Pull Request resolved: #34014 Test Plan: ### Test Preparation 1. Make sure you have a working version of E/App. 2. Open App/src/components/withWindowDimensions.js and update the constructor by changing this line: `this.onDimensionChange = _.debounce(this.onDimensionChange.bind(this), 100);` to `this.onDimensionChange = this.onDimensionChange.bind(this);` 3. Open the NewExpensify.xcodeproj in xCode. 4. Open the RCTDeviceInfo.mm file and replace it's contents with the file from this PR. 5. Select your device of choice (I suggest starting with iPad mini) and run the app though xCode. 6. From this point you can move to the test scenarios described below. ### iPad Mini tests: Reproduction + Fix test video (Test 1): https://youtu.be/jyzoNHLYHPo Reproduction + Fix test video (Test 2): https://youtu.be/CLimE-Fba-g **Test 1:** 1. Launch app in portrait, open chat - no sidebar visible. 7. Switch to landscape - sidebar shows. 8. Put app to background. 9. Put app back to foreground - make sure the side menu doesn't flicker. **Test 2:** 1. Launch app in portrait, open chat - no sidebar visible. 2. Switch to landscape - sidebar shows. 3. Put app to background. Switch orientation back to portrait. 4. Put app back to foreground - make sure the side menu hides again as it should be in portrait. ### iPad Pro tests: Reproduction + Fix test video (Test 3, Test 4): https://youtu.be/EJkUUQCiLRg iPad mini test 1 applies. Scenario 2 does not as the screen is too wide in both orientations and iPad pro shows sidebar always. **Test 3:** 1. launch the app. 2. Make sure you're in landscape mode. 3. See split screen with some other app. Make sure the side bar is visible. 4. Play with the size of the view, resize it a bit. When the view shrinks it should hide the sidebar, when it grows it should show it. 10. Move the app to background and back to foreground, please observe there are no flickers. **Test 4:** 1. Launch the app. 2. Make sure you're in landscape mode. 3. Make the multitasking view and make Expensify app a slide over app. 4. Move back to fullscreen/split screen. Make sure the menu is shown accordingly 5. Move the app to background and back to foreground, please observe there are no flickers. ### iPhone: Non reg with and without the fix video: https://youtu.be/kuv9in8vtbk Please perform standard smoke tests on transformation changes. Reviewed By: cipolleschi Differential Revision: D37239891 Pulled By: jacdebug fbshipit-source-id: e6090153820e921dcfb0d823e0377abd25225bdf
#34014) Summary: This fix solves a problem very well evaluated [here](Expensify/App#2727) as well as this [one](#29290). The issue is that when the app goes to background, in landscape mode, the RCTDeviceInfo code triggers an orientation change event that did not physically happen. Due to that, we get swapped values returned when going back to the app. I debugged the react-native code, and to me it seems that react native publishes the orientation change event one extra time when switching the state of the app to 'inactive'. Here is what is happening: 1. iPad is in landscape. 2. We move the app to inactive state. 3. Native Code queues portrait orientation change (no such change happened physically), and immediately after it triggers landscape change (same as we had in point 1). 4. We restore the app to active state. 5. The app receives two queued orientation change events, one after another. 6. The quick transition between portrait and landscape happens even though it never went back to portrait. Fresh `react-native init` app repro case can be found here: https://github.com/lbaldy/issue-34014-repro Video presenting the issue (recorded while working on: Expensify/App#2727 ): https://www.youtube.com/watch?v=nFDOml9M8w4 <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - Fix the way the orientation events are published, to avoid false publish on orientation change when app changes state to inactive Pull Request resolved: #34014 Test Plan: 1. Make sure you have a working version of E/App. 2. Open App/src/components/withWindowDimensions.js and update the constructor by changing this line: `this.onDimensionChange = _.debounce(this.onDimensionChange.bind(this), 100);` to `this.onDimensionChange = this.onDimensionChange.bind(this);` 3. Open the NewExpensify.xcodeproj in xCode. 4. Open the RCTDeviceInfo.mm file and replace it's contents with the file from this PR. 5. Select your device of choice (I suggest starting with iPad mini) and run the app though xCode. 6. From this point you can move to the test scenarios described below. Reproduction + Fix test video (Test 1): https://youtu.be/jyzoNHLYHPo Reproduction + Fix test video (Test 2): https://youtu.be/CLimE-Fba-g **Test 1:** 1. Launch app in portrait, open chat - no sidebar visible. 7. Switch to landscape - sidebar shows. 8. Put app to background. 9. Put app back to foreground - make sure the side menu doesn't flicker. **Test 2:** 1. Launch app in portrait, open chat - no sidebar visible. 2. Switch to landscape - sidebar shows. 3. Put app to background. Switch orientation back to portrait. 4. Put app back to foreground - make sure the side menu hides again as it should be in portrait. Reproduction + Fix test video (Test 3, Test 4): https://youtu.be/EJkUUQCiLRg iPad mini test 1 applies. Scenario 2 does not as the screen is too wide in both orientations and iPad pro shows sidebar always. **Test 3:** 1. launch the app. 2. Make sure you're in landscape mode. 3. See split screen with some other app. Make sure the side bar is visible. 4. Play with the size of the view, resize it a bit. When the view shrinks it should hide the sidebar, when it grows it should show it. 10. Move the app to background and back to foreground, please observe there are no flickers. **Test 4:** 1. Launch the app. 2. Make sure you're in landscape mode. 3. Make the multitasking view and make Expensify app a slide over app. 4. Move back to fullscreen/split screen. Make sure the menu is shown accordingly 5. Move the app to background and back to foreground, please observe there are no flickers. Non reg with and without the fix video: https://youtu.be/kuv9in8vtbk Please perform standard smoke tests on transformation changes. Reviewed By: cipolleschi Differential Revision: D37239891 Pulled By: jacdebug fbshipit-source-id: e6090153820e921dcfb0d823e0377abd25225bdf
facebook#34014) Summary: This fix solves a problem very well evaluated [here](Expensify/App#2727) as well as this [one](facebook#29290). The issue is that when the app goes to background, in landscape mode, the RCTDeviceInfo code triggers an orientation change event that did not physically happen. Due to that, we get swapped values returned when going back to the app. I debugged the react-native code, and to me it seems that react native publishes the orientation change event one extra time when switching the state of the app to 'inactive'. Here is what is happening: 1. iPad is in landscape. 2. We move the app to inactive state. 3. Native Code queues portrait orientation change (no such change happened physically), and immediately after it triggers landscape change (same as we had in point 1). 4. We restore the app to active state. 5. The app receives two queued orientation change events, one after another. 6. The quick transition between portrait and landscape happens even though it never went back to portrait. Fresh `react-native init` app repro case can be found here: https://github.com/lbaldy/issue-34014-repro Video presenting the issue (recorded while working on: Expensify/App#2727 ): https://www.youtube.com/watch?v=nFDOml9M8w4 <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - Fix the way the orientation events are published, to avoid false publish on orientation change when app changes state to inactive Pull Request resolved: facebook#34014 Test Plan: 1. Make sure you have a working version of E/App. 2. Open App/src/components/withWindowDimensions.js and update the constructor by changing this line: `this.onDimensionChange = _.debounce(this.onDimensionChange.bind(this), 100);` to `this.onDimensionChange = this.onDimensionChange.bind(this);` 3. Open the NewExpensify.xcodeproj in xCode. 4. Open the RCTDeviceInfo.mm file and replace it's contents with the file from this PR. 5. Select your device of choice (I suggest starting with iPad mini) and run the app though xCode. 6. From this point you can move to the test scenarios described below. Reproduction + Fix test video (Test 1): https://youtu.be/jyzoNHLYHPo Reproduction + Fix test video (Test 2): https://youtu.be/CLimE-Fba-g **Test 1:** 1. Launch app in portrait, open chat - no sidebar visible. 7. Switch to landscape - sidebar shows. 8. Put app to background. 9. Put app back to foreground - make sure the side menu doesn't flicker. **Test 2:** 1. Launch app in portrait, open chat - no sidebar visible. 2. Switch to landscape - sidebar shows. 3. Put app to background. Switch orientation back to portrait. 4. Put app back to foreground - make sure the side menu hides again as it should be in portrait. Reproduction + Fix test video (Test 3, Test 4): https://youtu.be/EJkUUQCiLRg iPad mini test 1 applies. Scenario 2 does not as the screen is too wide in both orientations and iPad pro shows sidebar always. **Test 3:** 1. launch the app. 2. Make sure you're in landscape mode. 3. See split screen with some other app. Make sure the side bar is visible. 4. Play with the size of the view, resize it a bit. When the view shrinks it should hide the sidebar, when it grows it should show it. 10. Move the app to background and back to foreground, please observe there are no flickers. **Test 4:** 1. Launch the app. 2. Make sure you're in landscape mode. 3. Make the multitasking view and make Expensify app a slide over app. 4. Move back to fullscreen/split screen. Make sure the menu is shown accordingly 5. Move the app to background and back to foreground, please observe there are no flickers. Non reg with and without the fix video: https://youtu.be/kuv9in8vtbk Please perform standard smoke tests on transformation changes. Reviewed By: cipolleschi Differential Revision: D37239891 Pulled By: jacdebug fbshipit-source-id: e6090153820e921dcfb0d823e0377abd25225bdf
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. |
This issue is still valid to this date. If any anyone is interested and want more information to start working, please let me know. |
I'm also getting incorrect info from I got here trying to reorient between portrait and landscape view for my app. I'm unable to get the In the process of trouble shooting I tested to see what the width/height would be in both landscape and portrait orientation by started the app while holding the phone in that orientation. Both output the following to the console Device Info$ react-native info [11:37:07]
warn Package @sentry/react-native contains invalid configuration: "dependency.platforms.ios.sharedLibraries" is not allowed,"dependency.hooks" is not allowed. Please verify it's properly linked using "react-native config" command and contact the package maintainers about this.
info Fetching system and libraries information...
System:
OS: macOS 13.3.1
CPU: (10) arm64 Apple M1 Pro
Memory: 82.44 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 18.15.0 - ~/.volta/tools/image/node/18.15.0/bin/node
Yarn: 3.5.0 - ~/.volta/tools/image/yarn/3.5.0/bin/yarn
npm: 9.5.0 - ~/.volta/tools/image/node/18.15.0/bin/npm
Watchman: 2023.05.15.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.12.1 - /Users/loi/.rvm/gems/ruby-3.0.0/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 22.4, iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4
Android SDK: Not Found
IDEs:
Android Studio: 2022.2 AI-222.4459.24.2221.9862592
Xcode: 14.3/14E222b - /usr/bin/xcodebuild
Languages:
Java: javac 20 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: 18.2.0 => 18.2.0
react-native: 0.71.6 => 0.71.6
react-native-macos: Not Found
npmGlobalPackages:
*react-native*: Not Found Example 1import React, { useCallback } from 'react'
import { StyleSheet, View } from 'react-native'
const styles = StyleSheet.create({
container: {
flex: 1,
},
})
const App = (props) => {
const { children } = props
const handleLayout = useCallback(
(event) => {
const { width, height } = event.nativeEvent.layout
console.log({width, height});
},
[]
)
return (
<View style={styles.container} onLayout={handleLayout}>
{children}
</View>
)
}
export default App Example 2import React, { useEffect } from "react";
import {
Text,
View,
StyleSheet,
Dimensions,
useWindowDimensions,
} from "react-native";
const App = ({children}) => {
const { height, width } = useWindowDimensions();
useEffect(() => {
const subscription = Dimensions.addEventListener(
"change",
({ window, screen }) => {
console.log('Hi');
console.log({ window, screen });
}
);
return () => subscription?.remove();
}, []);
console.log({ height, width, foo: "bar" });
return (
<View style={styles.container}>
<Text>Hi</Text>
{children}
<Text>Hi</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "white"
},
header: {
fontSize: 20,
marginBottom: 12,
},
});
export default App; Please advise~! Appreciate your help and thanks in advance! |
Hello, i am experiencing a similar issue on Ipad ... "useWindowDimensions" is not returning new screen size values after the first 90deg device rotation. With the second rotation and any following, the hook is returning new values but swapped (incorrect). My suspicion is, that this is maybe related to the Scene Logic, we have implemented with Carplay. Did you have a similar core refactoring? Greets, Robert |
We experienced same issues with swapped widths and heights on iOS devices. We are running React Native code in a custom UIWindow where we noticed that the bounds for that UIWindow do not change. This could probably be an iOS bug? We then proceeded to use |
I've also noticed this issue. Both Dimensions.get('window') and useWindowDimensions doesn't handle it properly, and as I can see it return previous values even if called multiple time after rotate is done... I found closed issue from 2016 that shows up the same problem. Does anyone know any way to handle it, maybe some custom hook? |
@gerwld A simple custom hook is not enough. It's likely caused by a delayed orientation change event, and in turn lead to a stale state returned by You may try building a custom Native Module that directly listens to the orientation change event. |
+1 |
+1 |
Description
When tested with iPad simulator, the
useWindowDimensions(...)
hook returns incorrect width and height.React Native version:
Run
react-native info
in your terminal and copy the results here.Steps To Reproduce
Provide a detailed list of steps that reproduce the issue.
react-native init
to create a new project.App.js
with the following codeExpected Results
"landscape"
instead of nothing happens."portrait"
on the screen."landscape"
instead of"portrait"
.Snack, code example, screenshot, or link to a repository:
It is not easy to show device orientation features in snack, I'll attach screen recordings below.
You may download the original video to pause for the rendered text.
Screen Recording 2020-07-07 at 7.39.07 PM.zip
The text was updated successfully, but these errors were encountered: