目录

  • 两种像素
  • 分辨率
  • RN如何做屏幕适配
  • 1. 尺寸相同,适配不同分辨率
  • 2. 分辨率相同,适配不同尺寸屏幕
  • 3. px转dp
  • 4. 总结
  • 最终适配方案
  • 尺寸优化
  • 1. 像素对齐
  • 2. 实现真正的1px的分割线
  • 3. dp转px

2倍屏,3倍屏,px,dp,这些概念因为不影响开发没有深入研究过,最近要写一个屏幕的工具类,就趁着这个机会彻底了解一下。

两种像素

  • 物理像素:

单位是px,是画面中最小的点(单位色块)。像素的大小是没有固定长度值,不同分辨率设备上1个单位像素色块的大小是不一样的。
px在任何情况下都代表物理像素

  • 逻辑像素

逻辑像素的单位有多种,dp是其中之一,如下栗子指的都是6寸的屏幕:
在非Retina屏, 1dp == 1px : 1寸宽有100个像素点
在2倍Retina屏,1dp == 2px : 1寸宽有200个像素点
在3倍Retina屏,1dp == 3px : 1寸宽有300个像素点

  • DPR

DPR(设备像素比率) = px(物理像素)/dp(逻辑像素)
在每英寸160点的显示器上,1dp = 1px,设计师一般会以该基准作图

分辨率

  1. 屏幕上共有多少像素点,例如:屏幕分辨率是1024×768,也就是说设备屏幕的水平方向上有1024个像素点,垂直方向上有768个像素点
  2. iOS默认的单位是pt,android默认单位是dp,这两都是逻辑像素,在绘制时会自动转化为物理像素

RN如何做屏幕适配

1. 尺寸相同,适配不同分辨率

因为RN默认单位是dp,不需要考虑这个因素,系统会根据DPR(设备像素比率)自动将dp转化成相应的物理像素值,比如:1dp,在2倍屏上被转化成2px,在3倍屏上被转化成3px,如下图

swift 一倍屏 两倍屏 三倍屏适配_swift 一倍屏 两倍屏 三倍屏适配

由此可得出如下两个结论:

  1. 尺寸固定,分辨率越高,像素点越小,内容就越清晰
  2. 尺寸固定,不同分辨率1dp的宽度值时一致的

补充:前端不支持dp/pt单位,起到类似作用的是rem,rem的思路跟上面一致,但那个转换过程需要自己手动配置

2. 分辨率相同,适配不同尺寸屏幕

此时因为分辨率相同所以像素个数也相同,但每px的尺寸相对于屏幕宽的比例是一致的,如下图:

swift 一倍屏 两倍屏 三倍屏适配_swift 一倍屏 两倍屏 三倍屏适配_02


由此可得出如下两个结论:

  1. 同分辨率下,虽然设置设备尺寸不同但1px相对于屏幕的比例却是一样的,如上图所示1dp都是屏幕的1/4,这正好符合我们的屏幕适配的定义
  2. 同分辨率下,尺寸越大,单位像素尺寸越大,内容越模糊

3. px转dp

前端朋友可能更习惯于px,需要将px转为dp

/* 转换公式
 *
 * deviceWidth是RN获取到的屏幕宽,单位是dp  
 * UI设计稿的宽度为750px
 * size就是设置的px值
 *
 * 前面的除法得到在当前设备上每1px等于多少dp
*/
deviceWidth / 750 * size

可能有朋友迷糊了,为啥要用750呢,这个取决于你们UI给的设计稿的宽度,如果设计稿为375,那么就除以375

4. 总结

在RN中,dp单位解决了适配分辨率的问题;dp最后转化的px解决了适配不同尺寸的问题;最后的px转dp解决了前端经常使用的单位问题

最终适配方案

function px(size) {
  if (size == 1) {   
    return StyleSheet.hairlineWidth;
  }
  return  PixelRatio.roundToNearestPixel(deviceWidth / 750 * size);
}

尺寸优化

1. 像素对齐

当设置的像素值是小数时,会导致在GPU渲染时,对没对齐的边缘,需要进行插值计算,这个插值计算的过程会有性能损耗,所以要用到PixelRatio.roundToNearestPixel方法

将布局大小(dp)四舍五入为与整数个像素对应的最近布局大小。例如,在PixelRatio为3的设备上PixelRatio.roundToNearestPixel(8.4) = 8.33,它恰好对应于(8.33 * 3)= 25像素
不是将dp转化为px

2. 实现真正的1px的分割线

若设置1dp,在1倍2倍3倍屏上分别渲染的真正像素分别是:1px,2px,3px,结果也不是我们想要的。

解决方式就是,当想要设置1px的线宽时,直接返回StyleSheet.hairlineWidth

  1. 当前平台上的最细的宽度。可以用作边框或是两个元素间的分隔线
  2. 该值并不是一个常量,他的单位是dp,但在不同分辨率上最后渲染出来的始终是1px的物理像素

3. dp转px

// 将布局大小(dp)转换为像素大小(px),保证返回一个整数
 PixelRatio.getPixelSizeForLayoutSize(dp)