iOS像素与点

作者: 小黑_Coder | 来源:发表于2017-01-10 00:49 被阅读410次

    iOS上的像素(Pixel)与点(Point)

    像素(Pixel)和点(Point)

    我们在讨论这个问题之前,最起码要搞懂什么是点(Point)和什么是(Pixel)这个几个概念

    • px:pixel像素,屏幕上显示的最小单位
    • pt:point点,是一个标准的长度单位,1pt=1/72inch
    • PPI(DPI):pixel per inch像素密度PPI,指每英尺的像素数,表示了清晰度

    1inch=2.54cm =25.4mm

    好概念就普及到这里了因为在装下去就要露馅了,今天有空为什么要说一说像素和点呢?因为在设计师验收的时候发现不合格(ps:自己都看不下去了),既然已经踩了坑,那就把过坑的方法拿出来分享一下吧(PS:鄙人学识短浅,哪有说的不对的地方还望大牛们多多指点)。

    Xib带来的一点坑

    场景

    设计师经常喜欢在用户名,密码等输入框下面给一个高度为1px的下划线。这个时候对于开发人员来讲可能直接使用约束在输入框下面添加一个view然后修改背景颜色,此时我们就顺利入坑了。

    xib.png

    看上去好像是达到了我们预期的效果。我们这时在使用代码来实现一下。

    //代码实现方式一
           for i in 0 ..< 5 {
                
               let view = UIView.init(frame: CGRect.init(x: 0, y: 200+CGFloat(i)*10, width: self.view.frame.width, height: 0.5))
               view.backgroundColor = UIColor.init(colorLiteralRed: 207.0/255.0, green: 181.0/255.0, blue: 107.0/255.0, alpha: 1)
               self.view.addSubview(view)
           }
            
    //代码实现方式二
           for i in 0 ..< 5 {
                
               let view = UIView.init(frame: CGRect.init(x: 0, y: 300+CGFloat(i)*10, width: self.view.frame.width, height: 1.0/UIScreen.main.scale))
               view.backgroundColor = UIColor.init(colorLiteralRed: 207.0/255.0, green: 181.0/255.0, blue: 107.0/255.0, alpha: 1)
               self.view.addSubview(view)
            } 
    

    效果

    iPhone 7上实验了一下,结果却并不是我们想要的

    result1.PNG

    对比发现Xib实现的下划线存在有点的变粗有点变细,这一点对于设计师当然是不能忍受的。当然非要使用Xib来完成这一项需求也是可以的,我们可以把xib中的约束拖成类的属性,然后使用代码对约束进行修改。这个解决方案我写在了代码中就不在这里详细介绍了,如果感兴趣可以尝试一下,当然个人不推荐使用修改约束的方法。

    分析

    iOS中,point独立于物理设备的逻辑坐标单位。iPhone 4之前non-retina屏幕的设备,一个point就代表一个像素;从iPhone 4iPhone 7,采用retina屏幕;一个point,代表2X2个像素;Plus的设备,一个point代表3X3个像素。

    • 绘图系统通常都会采用一个叫反锯齿antialiasing的技术,iOS也不例外。我们前面提到过像素是屏幕上显示的最小单位。屏幕有很多小的显示单元组成,简单理解一个单元就代表一个像素。如果要画一条黑线,条线刚好落在了一列或者一行显示单元之内,将会渲染出标准的一像素黑线。但如果线落在了两个行或列的中间时,那么会得到一条失真的线,其实是两个像素宽的灰线,我们可以看Apple给出的文档
      图片来自Apple官方文档.png

    Positions defined by whole-numbered points fall at the midpoint between pixels. For example, if you draw a one-pixel-wide vertical line from (1.0, 1.0) to (1.0, 10.0), you get a fuzzy grey line. If you draw a two-pixel-wide line, you get a solid black line because it fully covers two pixels (one on either side of the specified point). As a rule, lines that are an odd number of physical pixels wide appear softer than lines with widths measured in even numbers of physical pixels unless you adjust their position to make them cover pixels fully.

    • 一个英语超烂的人读了官方文档以后,加上自己的理解简单翻译如下。

    规定:奇数像素宽度的线在渲染的时候将会表现为柔和的宽度扩展到向上的整数宽度的线,除非你手动的调整线的位置,使线刚好落在一行或列的显示单元内。

    • 那么我们该怎么去让线与刚好落在一行或一列的显示单元内,请看官方给我的解决方案

    On a low-resolution display (with a scale factor of 1.0), a one-point-wide line is one pixel wide. To avoid antialiasing when you draw a one-point-wide horizontal or vertical line, if the line is an odd number of pixels in width, you must offset the position by 0.5 points to either side of a whole-numbered position. If the line is an even number of points in width, to avoid a fuzzy line, you must not do so.
    On a high-resolution display (with a scale factor of 2.0), a line that is one point wide is not antialiased at all because it occupies two full pixels (from -0.5 to +0.5). To draw a line that covers only a single physical pixel, you would need to make it 0.5 points in thickness and offset its position by 0.25 points. A comparison between the two types of screens is shown in Figure 1-4.

    • 没有自知之明的我,看完文档以后依然加上自己的理解给出了一个简单的翻译

    在非高清屏上,一个Point对应一个像素。为了防止antialiasing导致的奇数像素的线渲染时出现失真,你需要设置偏移0.5 Point。在高清屏幕上,要绘制一个像素的线,需要设置线宽为0.5 Point,同时设置偏移为0.25 Point。如果线宽为偶数Point的话,则不要去设置偏移,否则线条也会失真。

    图片来自Apple官方文档.png
    • 至此问题貌似都解决了,再想想为什么在非RetinaRetina屏幕上调整位置时值不一样,前者为0.5 Point,后者为0.25 Point,那么scale36/7 Plus设备又该调整多少呢?那我们就在回过头来看看下面这幅图,顶部标记为我们代码布局时的坐标。在非`Retina屏幕,我们要在(3,0)这个位置画一条一个像素宽的竖线时,由于渲染的最小单位是像素,而(3,0)这个坐标恰好位于两个像素中间,此时系统会对坐标3左右两列的像素对填充,为了不至于线显得太宽,线的颜色淡化。那么根据上述信息我们可以得出,如果要画出一个像素宽的线,就得把绘制的坐标移动到(2.5, 0)或者(3.5,0)这个位置,这样系统渲染的时候刚好可以填充一列像素,也就是标准的一个像素的线。

      图片来自网络. png
    • 基于上面的分析,我们可以得出“Scale为3的6 Plus”设备如果要绘制1个像素宽的线条时,位置调整也应该是0.5像素,对应该的Point计算如下:

    (1.f /UIScreen.main.scale) / 2;

    • 那么为什么在Xib中会出现粗细不一样,而使用代码却可以呢。因为在Xib设置约束之后系统不会因我们设置了奇数个像素点没有落在一行或一列的显示单元内,而给我们调整。但是我们使用代码编写的时候,系统在渲染的时候就会帮我们调整到一行或一列的显示单元内。

    最好的学习资料

    官方文档:https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html

    欢迎讨论

    email:huliuworld@yahoo.com
    相关代码:https://github.com/LHCoder2016/PixelAndPoint.git

    相关文章

      网友评论

      • 我只是个仙:没看太懂 ,而且感觉没头没尾的,最后到底是怎么解决的呢?
      • 郑一一一一:由于渲染的最小单位是像素,而(3,0)这个坐标恰好位于两个像素中间,此时系统会对坐标3左右两列的像素对填充,为了不至于线显得太宽,线的颜色淡化。这句话实在不懂!
      • 郑一一一一:有些地方 看不懂。
        小黑_Coder:@啊啦哈 可以提出来我们在探讨一下哦
      • 秋_明:这个点确实是的
      • 山水域:二货,英语有进步呀👏🏻

      本文标题:iOS像素与点

      本文链接:https://www.haomeiwen.com/subject/quqkbttx.html