ios - Swift - UIView 绘制 1 像素宽的线

标签 ios swift uiview drawing line

我正在尝试像这样使用 Swift 在 UIView 上画一条线:

CGContextSetLineWidth(context, 1.0)
CGContextBeginPath(context)
    CGContextMoveToPoint(context, x1, y1)
    CGContextAddLineToPoint(context, x2, y2)
CGContextStrokePath(context)

但是绘制的线是 2 像素宽。我尝试了另一种方式:

CGContextSetLineWidth(context, 0.5)
CGContextBeginPath(context)
    CGContextMoveToPoint(context, x1, y1)
    CGContextAddLineToPoint(context, x2, y2)
CGContextStrokePath(context)

但结果是一样的。 我做错了什么以及如何使用 Swift 在 UIView 上绘制一条 1 像素宽的线?

最佳答案

这里有两个问题:

  1. CoreGraphics 绘图函数以点(屏幕布局的单位,在所有设备上的近似物理尺寸是恒定的)而不是以像素为单位工作。每个点的像素数在屏幕比例不同的设备上是不同的:iPad 2 和 iPad mini 是 iOS 7 及更高版本中唯一支持的 1x 设备,iPhone 4、iPad 3、iPad mini 2 及更高版本为 2x,iPhone 6 除外/6s/7 Plus 是 3x。因此,如果您想要单设备像素的细线,则在大多数当前设备上需要 0.5 磅的线宽(在 iPhone 6 Plus 上需要 0.33 磅的线宽)。

  2. 一条线的宽度以一个点的正方形区域为中心。因此,如果您有一条从 (10.0, 10.0) 到 (10.0, 20.0) 的线,它实际上位于 x 坐标为 10.0 和 9.0 的像素之间 — 渲染时,抗锯齿将遮蔽 10.0 和 9.0 列的像素在 50% 的线条颜色下,而不是在 100% 处对一列进行着色。要解决此问题,您需要定位您的线条,使其完全位于一个像素内。 (设备像素,而不是布局点。)

因此,要获得一个像素的细线,您需要减小线宽并根据屏幕的比例因子改变所绘制的点的偏移量。这是执行此操作的测试用例的扩展:

// pass in the scale of your UIScreen
func drawHairline(in context: CGContext, scale: CGFloat, color: CGColor) {

    // pick which row/column of pixels to treat as the "center" of a point
    // through which to draw lines -- favor true center for odd scales, or
    // offset to the side for even scales so we fall on pixel boundaries
    let center: CGFloat
    if Int(scale) % 2 == 0 {
        center = 1 / (scale * 2)
    } else {
        center = 0
    }

    let offset = 0.5 - center // use the "center" choice to create an offset
    let p1 = CGPoint(x: 50 + offset, y: 50 + offset)
    let p2 = CGPoint(x: 50 + offset, y: 75 + offset)

    // draw line of minimal stroke width
    let width = 1 / scale
    context.setLineWidth(width)
    context.setStrokeColor(color)
    context.beginPath()
    context.move(to: p1)
    context.addLine(to: p2)
    context.strokePath()
}

centerChoice 计算概括了必须选择在哪个子点像素上绘制线条的问题。您必须通过点的中心(偏移 0.5)绘制以在 1x 显示器上遮蔽整个像素或在 3x 显示器上仅遮蔽该点的中间像素,但在 2x 显示器上偏移 0.5 位于两个像素之间这构成了一个点。因此,对于 2x,您必须选择偏移量 0.25 或偏移量 0.75 — center 行通常对偶数或奇数比例因子执行此操作。

注意#1:我将您的测试用例更改为绘制一条垂直线,因为这样更容易看到抗锯齿的效果。无论如何,对角线都会得到一些抗锯齿,但如果宽度和位置正确,垂直线或水平线将不会得到抗锯齿。

注意 #2:iPhone 6/6s/7 Plus 的逻辑比例为 3.0,物理显示比例约为 2.61 — 您可能想尝试使用 screen.scale screen.nativeScale 看看哪个能让你得到更好看的结果。

关于ios - Swift - UIView 绘制 1 像素宽的线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27385929/

相关文章:

ios - 使用 Sirikit 提高支付的安全性

ios - 在 Xcode 10 中构建时重置应用程序后 String.hashValue 不是唯一的

ios - 如何使用 Swift iOS 监听 UIReturnKeyType.Next

ios - 如何检查 CCSprite 中的像素是否透明

ios - 来自字典的 JSON 编码 [无法调用 'dataWithJSONObject ...]

swift - 将 UInt16 转换为 Int16 会发生程序崩溃

iOS - CoreData 错误导致空值

ios - 在一个公共(public) View Controller 中显示另一个 View Controller ,如滑动菜单

objective-c - xcode View 被调用并初始化但未显示

html - iOS 8.3 修复了 HTML 元素在输入焦点上消失的问题