Skip to content

Instantly share code, notes, and snippets.

@petrbela
Last active April 9, 2025 19:48
Show Gist options
  • Save petrbela/d859308b22a09b4233fd72e26f2f9725 to your computer and use it in GitHub Desktop.
Save petrbela/d859308b22a09b4233fd72e26f2f9725 to your computer and use it in GitHub Desktop.
// used for Expo Go
import {
Orientation,
addOrientationChangeListener,
getOrientationAsync,
removeOrientationChangeListener,
} from 'expo-screen-orientation'
import { useEffect, useState } from 'react'
import { Dimensions } from 'react-native'
/**
* Return actual window dimensions even when orientation changes.
*
* @see https://github.com/facebook/react-native/issues/29290
* @returns window dimensions
*/
export function useDimensions() {
const [dimensions, setDimensions] = useState(Dimensions.get('window'))
useEffect(() => {
getOrientationAsync().then((orientation) => {
setDimensions(fixDimensions(orientation))
})
const listener = addOrientationChangeListener(({ orientationInfo }) => {
setDimensions(fixDimensions(orientationInfo.orientation))
})
return () => {
removeOrientationChangeListener(listener)
}
}, [])
return dimensions
}
function fixDimensions(orientation: Orientation) {
const window = Dimensions.get('window')
if (
(orientation === Orientation.LANDSCAPE_LEFT ||
orientation === Orientation.LANDSCAPE_RIGHT) &&
window.width < window.height
) {
return { ...window, width: window.height, height: window.width }
} else if (
(orientation === Orientation.PORTRAIT_UP ||
orientation === Orientation.PORTRAIT_DOWN) &&
window.width > window.height
) {
return { ...window, width: window.height, height: window.width }
}
return window
}
// used for native build
import { useEffect, useState } from 'react'
import { Dimensions, useWindowDimensions } from 'react-native'
import {
orientation as Orientation,
addOrientationListener,
getOrientation,
removeOrientationListener,
} from 'react-native-orientation'
/**
* Return actual window dimensions even when orientation changes.
*
* @see https://github.com/facebook/react-native/issues/29290
* @returns window dimensions
*/
export function useDimensions() {
const windowDimensions = useWindowDimensions()
const [dimensions, setDimensions] = useState(windowDimensions)
function updateDimensions() {
getOrientation((err, orientation) => {
if (err) {
console.error(err)
} else {
setDimensions(fixDimensions(orientation))
}
})
}
useEffect(() => {
// Update dimensions when orientation changes
const orientationListener = (orientation: Orientation) => {
setDimensions(fixDimensions(orientation))
}
addOrientationListener(orientationListener)
return () => {
removeOrientationListener(orientationListener)
}
}, [])
useEffect(() => {
// Update dimensions when window size changes
// FIXME: on Mac (Designed for iPad), there's currently no native window size change event in UIKit, so the trigger is delayed until the window is blurred or focused
updateDimensions()
}, [windowDimensions])
return dimensions
}
function fixDimensions(orientation: Orientation) {
const window = Dimensions.get('window')
if (orientation === 'LANDSCAPE' && window.width < window.height) {
return { ...window, width: window.height, height: window.width }
} else if (
(orientation === 'PORTRAIT' || orientation === 'PORTRAITUPSIDEDOWN') &&
window.width > window.height
) {
return { ...window, width: window.height, height: window.width }
}
return window
}
// used for web
import { useWindowDimensions } from 'react-native'
export const useDimensions = useWindowDimensions
@petrbela
Copy link
Author

Just found out expo-screen-orientation is broken in native builds expo/expo#15009 so a different solution might be needed.

@vishnuc
Copy link

vishnuc commented Mar 1, 2025

Hi , did u find any solutions ?

@petrbela
Copy link
Author

petrbela commented Mar 1, 2025

I added an implementation using react-native-orientation that I use for native builds.

Since that native package can't be used when I test in Expo Go, I default to expo implementation by adding config.resolver.sourceExts.unshift('expo.ts', 'expo.tsx') to my metro.config.js that's used only by the Expo packager.

@vishnuc
Copy link

vishnuc commented Mar 1, 2025

hi , for me it works normally in all build.. i use expo 52.. did u try 52?

I use import * as ScreenOrientation from "expo-screen-orientation";

@petrbela
Copy link
Author

petrbela commented Apr 9, 2025

fwiw I've now switched to useSafeAreaFrame as described facebook/react-native#29290 (comment) which seems to work so far, is supported in Expo (Go) out of the box and looks much cleaner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment