iOS Retina屏幕0.5pt线宽颜色失真问题

项目中添加0.5pt线宽分隔线,在iPhone6/7/8(普通屏)及iPhone X(Retina屏)中显示有区别,在普通屏幕下显示正常,但在高清屏幕(右图)中会有失真现象


了解过是因为像素尺寸(px)跟开发尺寸(pt)区别造成的,却未仔细了解过,查询得知具体原因


在我们日常开发中,使用的frame等页面UI绘制中是以point为单位,也就是我们所说的逻辑坐标系
而在实际屏幕中是以pixel为基本测量单位,设备坐标系
因此在iOS中当我们使用Quartz,UIKit,CoreAnimation等框架时,所有的坐标系统采用Point来衡量。系统在实际渲染到设置时会帮助我们处理Point到Pixel的转换。

所以在大部分情况下我们不需要关注pixel,但在部分情况下则需要考虑到像素与点的转化,如绘制0.5pt(或是1像素)的分割线时


在非Retina屏幕中 1 point(pt)对应的就是一个像素pixel,即逻辑坐标系中的一个点等于设备中一个像素(1×1)
在Retina屏幕中 1 point(pt)对应则可能是2个或者3个,取决于系统设备的DPI,即逻辑坐标系中的一个点等于设备中四个像素(2×2),在屏幕比例scale大于等于3的设备时,1point等于9pixels


一开始处理失真的解决想法是通过屏幕比例来算出1像素对应的point,但实际结果依然没有变化,在高清屏幕中显示依旧为失真的黑色线条

原因在于绘图系统会采用antialiasing(反锯齿)的技术来获得良好的视觉效果
显示屏幕由很多小的显示单元组成,可以理解为一个单元就代表一个像素。如果要画一条黑线,条线刚好落在了一列或者一行显示显示单元之内,将会渲染出标准的一个像素的黑线,但如果线落在了两个行或列的中间时,那么会得到一条失真的线,其实是两个像素宽的灰线。

image.png

Positions definedbywhole-numbered points fall at the midpoint between pixels.Forexample,ifyou draw a one-pixel-wide vertical linefrom(1.0,1.0)to(1.0,10.0), yougeta fuzzy grey line.Ifyou draw a two-pixel-wide line, yougeta solid black line because it fully covers two pixels (oneoneither sideofthe specified point).Asa rule, lines that are an odd numberofphysical pixels wide appear softer than lineswithwidths measuredineven numbersofphysical pixels unless you adjust their positiontomake them cover pixels fully.

因此要解决Retina屏幕中设置一条0.5pt线条因反锯齿原因造成的线条失真问题时,需同时设置0.25point(0.5像素)的偏移,这样系统渲染的时候刚好可以填充完整一像素,也就是得到一条标准像素颜色变化的线条

#define APP_LINE_WIDTH    ([UIScreen scrnScale] >= 3 ? 0.75 : 0.5)

如果线宽为偶数Point的话,则不要去设置偏移,否则线条也会失真
如果没有特殊的需求,苹果不建议使用宽度为一个像素点的线,因为在视网膜屏幕上太细会看不清楚


image.png

Ona low-resolution display (witha scale factorof1.0), a one-point-wide lineisone pixel wide.Toavoid antialiasingwhenyou draw a one-point-wide horizontalorvertical line,ifthe lineisan odd numberofpixelsinwidth, you must offset the positionby0.5pointstoeither sideofa whole-numbered position.Ifthe lineisan even numberofpointsinwidth,toavoid a fuzzy line, you mustnotdoso.Ona high-resolution display (witha scale factorof2.0), a line thatisone point wideisnotantialiased at all because it occupies two full pixels (from-0.5to+0.5).Todraw a line that covers only asinglephysical pixel, you would needtomake it0.5pointsinthicknessandoffset its positionby0.25points. A comparison between the two typesofscreensisshowninFigure1-4.

你可能感兴趣的:(iOS Retina屏幕0.5pt线宽颜色失真问题)