最近在开发过程中遇到了一个问题,就是当我用22.1999…的约束(请注意这里是约束)设置一个CollectionView的左右边距时,在iPhone 8和iPhone X上绘制出来的左边分别为22和22.33,这微小的数值差距,导致了本该显示4个元素的CollectionView在iPhone X上只显示了3个,问题实例看这里。
为什么变成了22和22.33
iPhone 8 | iPhone X | |
---|---|---|
UIKit Size | 375*667 | 375*812 |
分辨率 | 750*1334 | 1125*2436 |
UIKit Scale factor | 2 | 3 |
由上面的表格我们可以看出,iPhone 8和iPhone X在UIKit Size的宽度上并没有什么不同,不同的点在于由分辨率导致的倍率上,iPhone 8是2,iPhone X是3。那也就是说在iPhone 8上,UIKit Size上横向的1代表着屏幕上横向的2个像素,反过来说就是,在iPhone 8上,1个像素对应的数值为0.5,也就是说iPhone 8上最小的绘制单位是0.5,那么同理,在iPhone X上最小的绘制单位是0.33。
iOS系统的针对像素的绘制采用四舍五入的方式,比如说22.1999…的小数位0.1999,在iPhone 8上相对于1个像素的基础数值为0.1999/0.5=0.3998
,0.3998<0.5
,丢弃,故实际显示的数值为22。在iPhone X上0.1999相对于一个像素的基础数值为0.1999/0.33=0.60575756
,0.60575756>0.5
,补充为1个像素,故在实际显示的数值为22.33,正是因为这个机制导致的微小差异使视图在不同的机型上显示出了差异。
为什么是约束
细心的同学可能发现,如果我直接使用frame进行布局,并不会有这样的异常,为什么在使用约束的时候会出现?
这是因为frame是你直接计算好后对应到屏幕上的,在有数值丢弃的位置刚好有相应的数值补充,这样就维持了一个平衡,导致总体占用的像素数不变。
约束采用的是先确定父视图的展示frame,然后子视图再根据父视图的frame和约束去计算自身要展示的frame,这里要注意的是父视图frame当中补充或者丢弃的部分在子视图或者其他同级的视图当中并没有对应的数值补充,这样就导致了这四舍五入引入的微小差距保留了下来,进而可能导致视图异常。
如何绘制好1像素
- 综合考虑的情况下尽量使用frame布局
- 2倍屏幕的1像素是0.5,3倍的屏幕是0.33,建议做区分
- 针对文中提到的偏差问题,建议视情况丢弃部分小数位
注意
部分计算为了方便省去了靠后的小数位,不影响计算结果。