有时候页面上需要绘制1像素的分隔线,可以通过添加 view 的方式,也可以通过 UIGraphicsGetCurrentContext 的方式实现。但是通过UIGraphicsGetCurrentContext实现的时候需要注意像素的问题。
在绘制1像素线之前,我们先来看一下绘制高度为50的线是什么样的效果。以下图均为模拟器上的截图放大后显示,红色为view的方式,黑色为UIGraphicsGetCurrentContext的方式,分别在2倍屏和3倍屏的效果。
let line1 = UIView(frame: CGRect(x: 0, y: 50, width: 100, height: 50))
line1.backgroundColor = .red
addSubview(line1)
paint.setLineWidth(50)
paint.move(to: CGPoint(x: 100, y: 50))
paint.addLine(to: CGPoint(x: 200, y: 50))
paint.setStrokeColor(red: 0, green: 0, blue: 0, alpha: 1)
paint.strokePath()
iPhone Xʀ: iPhone Xs Max:
从图中可以看出,paint.strokePath() 这个方式是居中绘制。
下面再看下绘制1像素的效果。
let line1 = UIView(frame: CGRect(x: 0, y: 1, width: 100, height: 1/UIScreen.main.scale))paint.setLineWidth(1/UIScreen.main.scale)
iPhone Xʀ: iPhone Xs Max:
由上看出,通过View的方式没有问题,通过paint绘制的会“失真”,出现两个像素的灰线。苹果官方的解释翻译后是:奇数像素宽度的线在渲染的时候将会表现为柔和的宽度扩展到向上的整数宽度的线,除非你手动的调整线的位置,使线刚好落在一行或列的显示单元内。
可以这么理解:苹果在绘制的时候,最低绘制单位为1个单元。由于paint是居中绘制,绘制1像素时,坐标相邻的两个单元内各占0.5像素,此时跨越两个单元,由于最低绘制为1个单元,所以绘制出了两个像素。如下图所示:
此图显示的是一条竖线。
如何解决呢?苹果给出的方案是设置偏移量,使绘制的1像素线在1个单元内。
我们可以这么处理,以paint绘制横线为例,使绘制的中心位置往下偏移0.5像素,这样中心位置就落在1个单元的中间位置,居中绘制时,上下各占0.5像素,此时正好占据1个单元,所以绘制的效果也正好是1像素。达到了和UIView的方式一样的效果。
0.5像素为 (1/UIScreen.main.scale/2)
let line1 = UIView(frame: CGRect(x: 0, y: 1, width: 100, height: 1/UIScreen.main.scale))
line1.backgroundColor = .red
addSubview(line1)
paint.setLineWidth(1/UIScreen.main.scale)
paint.move(to: CGPoint(x: 100, y: 1+(1/UIScreen.main.scale/2)))
paint.addLine(to: CGPoint(x: 200, y: 1+(1/UIScreen.main.scale/2)))
paint.setStrokeColor(red: 0, green: 0, blue: 0, alpha: 1)
paint.strokePath()
iPhone Xʀ: iPhone Xs Max:
接下来的任务就是把 (1/UIScreen.main.scale/2) 设置为一个常量,添加一个公用的方法,以便项目中使用就好了。