ReactNative获取设备屏幕尺寸

在做移动开发过程中,有时我们需要适配不同尺寸大小的屏幕。这里我们就需要到获取设备屏幕的大小。
由于我们是使用的 ReactNative 来开发手机 app,这里就介绍一下在 ReactNative 中如何获取到设备屏幕的分辨率的。
也算是对之前踩坑的总结吧。

在此之前需要先了解 ReactNative 中的尺寸计算单位,它并不是使用的px。http://facebook.github.io/react-native/releases/next/docs/pixelratio.html

使用 Dimensions 模块

在 ReactNative 中有一个 Dimensions 模块,通过它可以获取当前设备的屏幕分辨率。
参考: http://facebook.github.io/react-native/releases/next/docs/dimensions.html

1
var {height, width} = Dimensions.get('window');

刚开始时我也是使用这种方法来得到整个屏幕的分辨率的,感觉轻松搞定。然而这里面却有一个坑。

首先来看看 ios 和 android 中的界面结构:

ios-screen-struct
android-screen-struct

如图所示,屏幕的宽度计算比较简单,就是从左边到右边的距离即可。
然后就是屏幕的高度了,这里其实我们是需要获取到可用区域的高度。
如图所示,对于 ios 系统来说可用区域高度就是整个屏幕的高度减去 Status Bar 的高度;
对于 android 系统来说就是屏幕的高度减去 Status Bar 和 Soft Menu Bar 的高度。

获取 iOS 设备的屏幕分辨率

正如上面所说的,在 ios 下的计算方法为:

1
2
var WIDTH = Dimensions.get('window').width;
var HEIGHT = Dimensions.get('window').height - STATUS_BAR_HEIGHT;

在 ios 系统状态栏高度(STATUS_BAR_HEIGHT)通常为 20。
不过如果你设置了隐藏状态栏的话,那么 STATUS_BAR_HEIGHT 则为0。

以上是手机竖屏的情况,在横屏状态下则交换两个值:

1
2
var LANDSCAPE_WIDTH = HEIGHT + STATUS_BAR_HEIGHT;
var LANDSCAPE_HEIGHT = WIDTH - STATUS_BAR_HEIGHT;

到了这里虽然麻烦了一点,但是总体来说也还好。问题都解决了。
感觉生活是如此美好啊,然而这个世界上却还有一个系统名为 android。
它有着数不清种类屏幕大小的设备,然后瞬间感觉整个人都不好了。

获取 Android 设备的屏幕分辨率

如果按照 ios 下的方法来做,获取到 WIDTH 是没有问题,
但是 HEIGHT 的话还需要减去 Status Bar 和 Soft Menu Bar 的高度。
因此我们还需要获取到状态栏的高度(STATUS_BAR_HEIGHT)和虚拟按钮的高度(SOFT_MENU_BAR_HEIGHT)。

这里我们使用react-native-extra-dimensions-android这个库。

1
2
3
4
5
6
const ExtraDimensions = require('react-native-extra-dimensions-android');
const STATUS_BAR_HEIGHT = ExtraDimensions.get('STATUS_BAR_HEIGHT');
const SOFT_MENU_BAR_HEIGHT = ExtraDimensions.get('SOFT_MENU_BAR_HEIGHT');
const WIDTH = ExtraDimensions.get('REAL_WINDOW_WIDTH');
const HEIGHT = ExtraDimensions.get('REAL_WINDOW_HEIGHT') - STATUS_BAR_HEIGHT - SOFT_MENU_BAR_HEIGHT;

以上是设备竖屏的结果,在横屏下你以为是不是只需要交换两个值就搞定了呢。

1
2
var LANDSCAPE_WIDTH = HEIGHT + STATUS_BAR_HEIGHT;
var LANDSCAPE_HEIGHT = WIDTH - STATUS_BAR_HEIGHT;

Naive!!如果这么轻松就搞定了的话,android就不叫做android了。

先来看看下面两张图片吧,分别是一个android平板设备在横屏和竖屏状态下的截图:

android-pad-landscape
android-pad-portrait

你把你手中的 android 手机分别进入横屏和竖屏状态下,再对照上面两张图片你会发现什么。
没错的,在平板设备上屏幕旋转之后 Soft Menu Bar 也跟着旋转了,
而在手机设备上 Soft Menu Bar 是始终固定在手机底部的。

尼玛,太坑爹了。看到这里瞬间呕血三升,要适配手机跟平板实现是太麻烦了。
以下是我的解决办法,先检查当前设备是否为平板,然后再分别处理。
至于平板的判断方法就自己想办法了,我的方法也不一定准。

1
2
3
4
5
6
7
if (isPad) {
LANDSCAPE_WIDTH = HEIGHT + STATUS_BAR_HEIGHT + SOFT_MENU_BAR_HEIGHT;
LANDSCAPE_HEIGHT = WIDTH - STATUS_BAR_HEIGHT - SOFT_MENU_BAR_HEIGHT;
} else {
LANDSCAPE_WIDTH = HEIGHT + STATUS_BAR_HEIGHT;
LANDSCAPE_HEIGHT = WIDTH - STATUS_BAR_HEIGHT;
}

以上是在 android 下遇到的第一个大坑。

到了这里我以为一切都该结束了吧,然而没想到还有一种手机叫做魅族。如下图:

Mezu-smart-bar

在屏幕右下角其实是有一个按钮的,然而左图所示的,该按钮被魅族手机的 Smart Bar 遮住了。
进入系统设置将 Smart Bar 隐藏后效果如右图所示。

看到这里又吐了两口老血,此为第二个大坑。

1
2
3
4
5
6
7
8
9
10
11
12
13
const SMART_BAR_HEIGHT = ExtraDimensions.get('SMART_BAR_HEIGHT');
if (SMART_BAR_HEIGHT) {
HEIGHT -= SMART_BAR_HEIGHT;
}
....
// 在上面 LANDSCAPE 的计算结果上再作如下处理
if (SMART_BAR_HEIGHT) {
LANDSCAPE_WIDTH += SMART_BAR_HEIGHT;
LANDSCAPE_HEIGHT -= SMART_BAR_HEIGHT;
}

在魅族的手机上计算屏幕高度时还需要再减去 Smart Bar 的高度,
同时还需要注意的是, Smart Bar 跟平板上的Soft Menu Bar 一样会随着屏幕旋转而转动的。

最后还有一点需要注意的是,在安装 react-native-extra-dimensions-android 库时不能直接使用 npm install --save react-native-extra-dimensions-android 进行安装,
而是需要直接通过 git 仓库来安装: npm install --save git+https://github.com/jaysoo/react-native-extra-dimensions-android.git

因为在 npm 上 react-native-extra-dimensions-android 的最新版为 0.17.0,
SMART_BAR_HEIGHT 的功能是在此之后才添加进来的。

在库的版本上面又被坑了一下。