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

Dimensions.get('window').height returns wrong height on Android with notch #23693

Closed
onitzschke opened this issue Feb 28, 2019 · 75 comments
Closed

Comments

@onitzschke
Copy link

🐛 Bug Report

Dimensions.get('window').height returns wrong height on Android with notch
Device: Android One Mi A2 Lite

Environment

React Native Environment Info:
System:
OS: macOS 10.14.3
CPU: (12) x64 Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz
Memory: 1013.34 MB / 16.00 GB
Shell: 5.3 - /bin/zsh
Binaries:
Node: 11.6.0 - /usr/local/bin/node
Yarn: 1.7.0 - /usr/local/bin/yarn
npm: 6.8.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
Android SDK:
API Levels: 18, 23, 25, 26, 27, 28
Build Tools: 19.1.0, 20.0.0, 21.1.2, 22.0.1, 23.0.1, 23.0.2, 23.0.3, 24.0.0, 24.0.1, 24.0.2, 24.0.3, 25.0.0, 25.0.1, 25.0.2, 25.0.3, 26.0.0, 26.0.1, 26.0.2, 26.0.3, 27.0.0, 27.0.1, 27.0.2, 27.0.3, 28.0.0, 28.0.0, 28.0.0, 28.0.1, 28.0.2, 28.0.3
System Images: android-21 | Intel x86 Atom, android-21 | Google APIs Intel x86 Atom, android-23 | Google APIs Intel x86 Atom, android-23 | Google APIs Intel x86 Atom_64, android-25 | Google APIs ARM EABI v7a, android-27 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom, android-28 | Google Play Intel x86 Atom_64
IDEs:
Android Studio: 3.3 AI-182.5107.16.33.5264788
Xcode: /undefined - /usr/bin/xcodebuild
npmPackages:
react: 16.8.3 => 16.8.3
react-native: ^0.58.5 => 0.58.5
npmGlobalPackages:
create-react-native-app: 2.0.2
react-native-cli: 2.0.1
react-native-git-upgrade: 0.2.7

@hramos
Copy link
Contributor

hramos commented Feb 28, 2019

Can you provide more information? What value did the API return vs what was expected, for example.

@onitzschke
Copy link
Author

@hramos
Xiaomi Mi A2 lite:
Dimensions.get('window').height) => 681
Dimensions.get('screen').height) => 760
StatusBar.currentHeight => 31
Google Pixel 3:
Dimensions.get('window').height) => 737.4545454545455
Dimensions.get('screen').height) => 785.4545454545455
StatusBar.currentHeight => 24

Expect Dimensions.get('window').height) === 705 on Xiaomi Mi A2 lite to get the same Layout as on Google Pixel 3.

@grabbou
Copy link
Contributor

grabbou commented Mar 19, 2019

I believe this is related to issues with Dimensions.get('window') that I outlined here: #14887 (comment)

@terryttsai
Copy link

terryttsai commented Mar 21, 2019

Hi I'm seeing the same issue. Dimensions.get('window').height returns the wrong dimensions for me as well on my Essential Phone.

Dimensions.get('screen').height: 853.3333333333334
Dimensions.get('window').height: 759.6666666666666

So I took a screenshot and measured out the pixels. I measured the soft menu bar to be 48 logical pixels. So I expect Dimensions.get('window').height to return 853.333 - 48 = 805.333 but instead I get 759.666. I don't subtract the status bar height because according to the docs, Dimensions.get('window').height should include the status bar height if the status bar is translucent, which it is.

@ouabing
Copy link

ouabing commented Mar 25, 2019

Same issue on Mi 8 Lite.

@Martijnkerr
Copy link

Issue is on the new Samsung s10 model too.

@alexandrius
Copy link

My workaround was to calculate root view height with onLayout.

@andrey-shostik
Copy link

same on redmi note 7

@danilojpferreira
Copy link

I fix this like this:
Import { Dimensions, StatusBar } from 'react-native';

static height = Platform.OS === 'android' ? Dimensions.get('screen').height - StatusBar.currentHeight : Dimensions.get('window').height;

@franzwarning
Copy link

True on Samsung Galaxy s10 model.

@danilojpferreira
Copy link

I fix this like this:
Import { Dimensions, StatusBar } from 'react-native';

static height = Platform.OS === 'android' ? Dimensions.get('screen').height - StatusBar.currentHeight : Dimensions.get('window').height;

I trying now fix (temporarily)like this:
Import { Dimensions, StatusBar } from 'react-native';

static height = Platform.OS === 'android' && Platform.Version > 26 ? Dimensions.get('screen').height - StatusBar.currentHeight : Dimensions.get('window').height;

fhelwanger added a commit to Secullum/secullum-react-native-ui that referenced this issue Jul 10, 2019
@rahamin1
Copy link

rahamin1 commented Aug 7, 2019

Same problem with react-native 0.59.9, react 16.8.3

Dimensions.get('window').height returns:

  • 598 on LG V20 (should be 640), StatusBar.currentHeight returns 24.
  • 616 on Xiaomi Mi A1 (should be 640), StatusBar.currentHeight returns 24.

React native info:

React Native Environment Info:
System:
OS: Windows 10
CPU: (8) x64 Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
Memory: 1.80 GB / 7.87 GB
Binaries:
Yarn: 1.16.0 - C:\Users\yossi\AppData\Roaming\npm\yarn.CMD
npm: 6.1.0 - C:\Program Files\nodejs\npm.CMD
IDEs:
Android Studio: Version 3.3.0.0 AI-182.5107.16.33.5314842

@dhruvdangi
Copy link

dhruvdangi commented Aug 21, 2019

Based on the phones I've tested, for devices giving wrong height, Dimensions.get('screen').height is not equal to Dimensions.get('window').height.
If StatusBar.currentHeight > 24, we consider that it's a device with a notch
Here is a temporary fix that I'm using:

      Platform.OS !== 'ios' && Dimensions.get('screen').height !== Dimensions.get('window').height && StatusBar.currentHeight > 24
        ? Dimensions.get('window').height - StatusBar.currentHeight
        : Dimensions.get('window').height

@andrey-shostik
Copy link

@dhruvdangi exist another case with bottom navigation bar, its can be hid or showed.

@alexandrius
Copy link

alexandrius commented Aug 21, 2019

Just create something like this in app render function. There's small startup speed impact but solves the height issue

if (this.state.windowHeight === 0) {
    return <View onLayout={({ nativeEvent }) => {
        const windowHeight = nativeEvent.layout.height;
        Defaults.windowHeight = windowHeight;
        this.setState({ windowHeight })
    }} style={{ flex: 1 }} />
}

@jakobinn
Copy link

You can use the following package to fix this issue:
https://github.com/Sunhat/react-native-extra-dimensions-android

@stale
Copy link

stale bot commented Dec 13, 2019

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@paradite
Copy link

paradite commented Feb 10, 2022

@valeriik I tried your solution, it worked on iPhone 8 simulator, but not Samsung S21 (real device).
Evidently my solution is also not correct, so I will try on other devices to test further.
Maybe you can run your tests again, see my comment below:

@paradite
Copy link

@valeriik actually, I noticed that you used initialWindowMetrics.insets and initialWindowMetrics.frame instead of hooks useSafeAreaInsets() and useSafeAreaFrame().

I tested them and they have different values for Android:
Android:

initialWindowMetrics Object {
  "frame": Object {
    "height": 752,
    "width": 360,
    "x": 0,
    "y": 0,
  },
  "insets": Object {
    "bottom": 48,
    "left": 0,
    "right": 0,
    "top": 26.66666603088379,
  },
}
frame Object {
  "height": 752,
  "width": 360,
  "x": 0,
  "y": 0,
}
insets Object {
  "bottom": 0, // different here
  "left": 0,
  "right": 0,
  "top": 26.66666603088379,
}

ios:

initialWindowMetrics Object {
  "frame": Object {
    "height": 667,
    "width": 375,
    "x": 0,
    "y": 0,
  },
  "insets": Object {
    "bottom": 0,
    "left": 0,
    "right": 0,
    "top": 20,
  },
}
frame Object {
  "height": 667,
  "width": 375,
  "x": 0,
  "y": 0,
}
insets Object {
  "bottom": 0,
  "left": 0,
  "right": 0,
  "top": 20,
}

@njho
Copy link

njho commented Feb 25, 2022

Subscribed. @valeriik and others thanks for the research

@kotsh23
Copy link

kotsh23 commented Apr 18, 2022

const [itemHeight, setItemHeight] = useState(
    Platform.OS === "android" && Platform.Version < 30
      ? Dimensions.get("window").height - StatusBar.currentHeight
      : Dimensions.get("window").height
  );

@cristianoccazinsp
Copy link
Contributor

Why is this closed? StatusBar.currentHeight still gives wrong values on various Android devices (specifically, those with Notch). It's basically impossible to use Dimensions and StatusBar.currentHeight to determine height of usable screen space.

Further, the react-native rendering engine also has the same calculation issues. On some devices, trying to get something auto adjust its height up to 100% will end up rendered outside the screen on some devices.

@yahacom
Copy link

yahacom commented Jun 20, 2022

Encountered same issue.
Tested on two phones - both Android API 31.
And Dimensions.get('window').height returns different values. In one case it include value of StatusBar.currentHeight (and this value cover full screen height), in another - doesn't (and I have empty space on bottom). And here no any flags to determine relations of this behaviour.

@lucasdallabeneta
Copy link

only solution that worked for me:

import { Platform } from 'react-native'
import { initialWindowMetrics } from 'react-native-safe-area-context'

const USABLE_HEIGHT =
            Platform.OS === 'ios'
                ? initialWindowMetrics.frame.height -
                  initialWindowMetrics.insets.bottom
                : initialWindowMetrics.frame.height;

worked on: all iphones, samsung galaxy s20fe, samsung galaxy a9, redmi note 7 and motorola moto g5.

@julianklumpers
Copy link

if you do not want to install a library to get the insets of SafeAreaView you can use the following.

import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'

export const getScreenMetricsForSafeArea = () => {
  const { frame, insets } = TurboModuleRegistry.get('RNCSafeAreaContext').initialWindowMetrics
  const { top, left, right, bottom } = insets

  return { width: frame.width - (right + left), height: frame.height - (bottom + top) }
}

@InceptSolutions
Copy link

An easy fix that worked for us on both Samsung S7 and Samsung A31 is the following:

const height = Dimensions.get("window").height;
const isSame = height == Dimensions.get("screen").height;
const correctHeight = isSame ? height - StatusBar.currentHeight : height;

@lfjnascimento
Copy link

depending on the problem this might help, take the dimensions of the screen and not the window.

import { Dimensions } from 'react-native';
const { height: screenHeight, width: screenWidth } = Dimensions.get('screen');

@iway1-hstk
Copy link

iway1-hstk commented Aug 7, 2022

Right now the best solution is just measure the screen yourself, and pass into a context:

const Context = React.createContext();

export default function MyApp() {
    const [appHeight, setAppHeight] = useState(Dimensions.get('window').height);
    return (
        <Context.Provider value={appHeight}>
            <View style={{flex: 1}} onLayout={(e)=>setAppHeight(e.nativeEvent.layout.height)}>
                <RestOfApp/>
            </View>
        </Context.Provider>
    )
}

export function useActualHeight() {
    return useContext(Context);
}

@giorgiobeggiora
Copy link

giorgiobeggiora commented Dec 28, 2022

why the hell was this closed? the issue is not fixed, and it's super important

@sirmong
Copy link

sirmong commented Dec 29, 2022

Still experiencing issues when trying to calculate available space

@AhmedAbuelenin
Copy link

After some testing on different android versions and different devices this what I got.
from android version 10 and upwards window height is not including status bar height (fyi status bar height is including notch if exist as far as I tested)
below version 10 window height is including status bar height
we can summarize the above as like:

const WINDOW_HEIGHT =
  Platform.OS === 'android' && Platform.Version  >= 29   ? 
  Dimensions.get('window').height + StatusBar.currentHeight
    : Dimensions.get('window').height; 

note: WINDOW_HEIGHT on emulator includes status bar height I tested this for a few versions 30, 31, 33 which is different from the real devices as mentioned above.

Hope this help someone.

@eagleblack
Copy link

I a still facing this issue

@Colossus
Copy link

This is still not working. Window and screen heights return almost random values and are close to useless

@Colossus
Copy link

@iway1-hstk immediate Nobel prize for this solution

@WilcoBreedt
Copy link

WilcoBreedt commented Jun 8, 2023

Resolved the issue with the following code, which seems to be working well

Custom hook with a context

import React, { useContext, useState } from 'react';
import { Dimensions, SafeAreaView, StyleSheet, View } from 'react-native';

const ScreenDimensionsContext = React.createContext(null);

export const useDimensions = () => {
  const dimensions = useContext(ScreenDimensionsContext);
  return dimensions;
};

export const ScreenDimensionsProvider = ({ children, onDimensions }) => {
  const [dimensions, setDimensions] = useState(Dimensions.get('window'));
  const onLayout = (layout) => {
    if (onDimensions) {
      onDimensions(layout);
    }
    setDimensions(layout);
  };
  return (
    <ScreenDimensionsContext.Provider value={dimensions}>
      <SafeAreaView style={styles.flex}>
        <View
          style={styles.flex}
          onLayout={(e) => onLayout(e.nativeEvent.layout)}>
          {children}
        </View>
      </SafeAreaView>
    </ScreenDimensionsContext.Provider>
  );
};

const styles = StyleSheet.create({
  flex: {
    flex: 1,
  },
});

Use the context anywhere in your app and wrap your App.js in the Context
App.js

const App = () => {
const [height, setHeight] = useState();
return (
 <ScreenDimensionsProvider onDimensions={layout => setHeight(layout.height)}>
    <View style={{height}}>
        <RestOfApp />
    </View>
 </ScreenDimensionsProvider>
)

Anywhere else in your app

const RandomComponent = () => {
    const { height } = useDimensions();
    return <View style={{height}} />
}

@sipotat
Copy link

sipotat commented Jul 13, 2023

{layout => setHeight(layout.height)}>

Nice implementation. I just won't have SafeAreaView there, as it might be required in some screens and not in others.

@Chasty
Copy link

Chasty commented Aug 4, 2023

@iway1-hstk Amazing!!

@deniska69
Copy link

deniska69 commented Apr 18, 2024

Right now the best solution is just measure the screen yourself, and pass into a context:

const Context = React.createContext();

export default function MyApp() {
    const [appHeight, setAppHeight] = useState(Dimensions.get('window').height);
    return (
        <Context.Provider value={appHeight}>
            <View style={{flex: 1}} onLayout={(e)=>setAppHeight(e.nativeEvent.layout.height)}>
                <RestOfApp/>
            </View>
        </Context.Provider>
    )
}

export function useActualHeight() {
    return useContext(Context);
}

great solution! How else can I get this value NOT through a hook...

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

No branches or pull requests