点和像素

iOS 开发中,咱们布局一个 UIView 和 CoreGraphics 制作内容的时分,运用的单位是点(Point, 缩写 pt),而屏幕上的显现单位是像素(Pixel, 缩写 px)。

点和像素的换算规矩取决于屏幕的精细程度(PPI:屏幕上每英寸能够显现的像素点的数量),比如:

  • iPhone 3GS 中一点等于一像素
  • iPhone 4 中一点等于两像素
  • iPhone 6 Plus 中一点等于三像素

这个份额值咱们能够经过 CGFloat screenScale = [UIScreen mainScreen].scale 获取 。

什么是像素对齐

通常咱们指定一个 UIView 的 frame 会选用整数,由于点是像素的整数倍,所以这里像素是对齐的。

可是有的时分咱们的 frame 是经过计算出来的,就会出现小数,这个小数乘以 screenScale 得出的数值或许不是整数,这便是像素不对齐。

还有一种特殊的像素不对齐,是运用 CoreGraphics 制作内容时特有的,后面会具体说明。

UIView 的像素对齐

UILabel 的试验

咱们设置一个 UILabel :

UILabel *label = [[UILabel alloc] init];
label.text = @"UIView 的像素不对齐";
label.frame = CGRectMake(100, 100, 300, 500.001);
[self.view addSubview:label];

经过 iPhone 13 Pro Max 的模拟器翻开,在模拟器菜单中翻开 Debug – Color Misaligned Images 选项,你会发现这个 UILabel 的背景变成黄色:

聊聊 iOS 中的像素对齐

这是由于系统发现了 500.001 是一个像素不对齐的高度,将它标记它为黄色。

相同的,(100.1, 100, 300, 500),(100, 100.1, 300, 500) 都会有问题,修正为 (100, 100, 300, 500) 就没问题了。

还有 (100, 100, 300, 500.33333) 也是没问题的,由于 500.33333 * 3 = 1501 是整数。

神奇的是,(100, 100, 300.1, 500) 是没问题的,猜测是 UILabel 的主动宽度导致(没有验证)。

不对齐会怎样样

有同学或许会问,对齐不对齐会有什么问题呢?好像也没什么影响,看起来上面的 UILable 也显现很正常。

咱们选用「像素眼」来看看:(100, 100, 300, 500) vs (100, 100, 300, 500.1)

聊聊 iOS 中的像素对齐

很明显,右边指定的高度高,烘托的时分需要多填充一个像素,而填充内容是一些半透明的像素,片面来说便是「右边糊了」。

再看:(100, 100, 300, 500) vs (100.1, 100, 300, 500)

聊聊 iOS 中的像素对齐

这比照就更加夸张了,各种细节纷歧样,这是 x 处于像素点的中心位置,成果引发了更多抗锯齿来补充过渡色彩。

为什么会糊

让咱们再进一步查询一下为什么会糊?

之前有个遍及猜测,当咱们设置 x 为 100.1 或许 100.9 的时分,系统会主动帮咱们取整数像素单位来显现,这对吗?

对的,可是跟咱们想的或许有点纷歧样。咱们来比照一下 (100.1, 100, 300, 500) vs (100.9, 100, 300, 500):

聊聊 iOS 中的像素对齐

咱们能够很显著的发现,最左边那条竖线的色彩纷歧致,这是为什么呢?

先用苹果官方的话来解释一下:

聊聊 iOS 中的像素对齐

简略了解一下便是,假如你非得从 0.5 像素的位置开始画线,系统也会帮你画,仅仅会触发抗锯齿(antialiasing),也便是会帮你把半个像素补齐到一个像素

补齐规矩是什么呢?

苹果没说,我依据试验定论猜测一下:依据该像素的占用面积的份额乘上原始色彩烘托出一个新的像素,比如苹果这个示例中便是 0.5 * 黑色,得出一个灰色。

结合上述论证与猜测,能够估测出上面文字 100.1 vs 100.9 竖线色彩纷歧的问题了。

聊聊 iOS 中的像素对齐

依据咱们前面的估测,100.1 占了 90% 像素面积,所以便是 90% 色彩深度,而 100.9 占了 10% 像素面积,也便是 10% 色彩深度。

所以,肉眼可见 100.1 比 100.9 深了许多。

其他视图

假如去测验其他视图的状况,能够发现 UIImageView,UIButton 只需设置了图片或文字,都会有上述状况。

一个 UIView 只设置了背景色彩,那么像素不对齐也不会有什么问题。可是,用 CoreGraphics 画上一条蓝线,就会出现问题了。

聊聊 iOS 中的像素对齐

所以得出定论:UIView 在有内容的状况下,像素不对齐就会触发抗锯齿,就会导致含糊现象。假如没有内容,仅仅设置了背景色则不会有问题。

CoreGraphics 的像素对齐

CoreGraphics 的像素对齐问题,又是什么状况呢?

假设咱们用 CoreGraphics 在 (3, 0 ) 到 (3, 5) 画一条一像素宽的线时,这条线会落在哪里?

让咱们魔改一下苹果的原图,会更好了解:

聊聊 iOS 中的像素对齐

很明显,一倍屏的状况下,是在第三个点(point)上左右平分半个像素。

半个像素,是不是想起了什么?没错,触发了抗锯齿,所以你的一像素黑线变成了二像素灰线。

怎样处理呢?有两个方法:

  1. 向左或向右移动半个像素,在不同屏幕下通用公式是: (1 / screenScale / 2)
  2. 把线的宽度补齐到两个像素,这样你会获得一条两个像素的黑线

推广一下:运用 CoreGraphics 制作奇数像素宽/高度线的时分,像素不对齐,会触发抗锯齿,导致含糊。

注意,偶数宽/高度的状况下,由于制作内容会均匀地落在坐标两头的像素点中,不需要也不能去做奇数时的处理计划。

再来魔改一下苹果的图,便利大家了解偶数的状况:

聊聊 iOS 中的像素对齐

终究还有一个点简单搞错,CoreGraphics 制作问题不要运用到 UIView 系统中。

由于 CoreGraphics 画线的时分在宽度上是没有方向性的,所以在 x 点画一条线的时分,是以 x 为中线,左右平均分配线宽。

而 UIView 在布局的时分是有坐标系的,当咱们指定一个 (3, 0, 1, 10) 的矩形框的时分(一倍屏),能够准确地在 3 像素开始向右边画出一个一像素宽的矩形(也便是一像素线)。

总结

所以,再次提炼一下「像素对齐」:当咱们制作视图时,应该让内容填满像素格。否则会触发了抗锯齿,或许导致内容含糊。

参阅文档

  • iOS Drawing Concepts
  • iOS 制作1像素的线
  • iOS优化:处理iOS中像素不对齐问题
  • iOS Color Misaligned Images优化
  • Aligned UIViews*