23

这是一个简单的绘图

    

- (void)drawRect:(CGRect)rect
{
    //vertical line with 1 px stroking
    UIBezierPath *vertLine = [[UIBezierPath alloc] init];
    [vertLine moveToPoint:CGPointMake(20.0, 10.0)];
    [vertLine addLineToPoint:CGPointMake(20.0, 400.0)];
    vertLine.lineWidth = 1.0;
    [[UIColor blackColor] setStroke];
    [vertLine stroke];

    //vertical rectangle 1px width 
    UIBezierPath *vertRect= [UIBezierPath bezierPathWithRect:CGRectMake(40.0, 10.0, 1.0, 390.0)];
    [[UIColor blackColor] setFill];
    [vertRect fill];

}

在非视网膜 3GS 和模拟器上,第一行模糊,看起来比 1 px 宽,但第二行清晰。

不幸的是,我既没有 iPhone4 也没有新的 iPad 来测试,但在视网膜模拟器上,两条线看起来都一样。

问题:对于非视网膜和视网膜设备,矩形而不是描边是获得相同结果的唯一方法吗?

4

2 回答 2

53

您正在填充矩形的内部,但您正在从中心抚摸线条。由于这两种情况下的坐标(矩形的角以及直线中的起点和终点坐标)都定义为整数值(没有分数),因此坐标位于精确的点边界上。

在谈到线的点时,我在上面说“坐标”,以免将它们与屏幕上的点混淆。出于同样的原因,我还说“点边界”而不是“像素边界”。iOS 用所谓的“点”而不是像素来定义它的坐标和所有点。点是与分辨率无关的测量。视网膜和非视网膜设备在屏幕上的点数相同,只是它们对应的实际像素数不同。

让我们看一下与填充角位于点边界上的矩形相比,抚摸位于点边界上的线(如您的问题):

在下面的插图中,我在非视网膜屏幕和视网膜屏幕上用黑色抚摸一条线并用橙色填充一个矩形。我还用蓝色勾勒出了线条和矩形。在这两种情况下,您都可以看到该分辨率的点大小并将其与实际像素网格进行比较。

在非视网膜情况下,您可以看到尝试使用 1 点线(在这种情况下对应于 1 像素线宽)从中心描边线将填充顶部的一半像素和像素上的一半以下。由于像素仅填充了一半,因此这些像素的不透明度为 50%。这会导致颜色变浅(在白色背景上)。由于顶部和下方的像素都是填充的,因此抚摸填充顶部和下方的像素。这使得线条看起来好像是 2 个像素宽而不是 1 个像素。

您可以快速将其与内部填充的矩形进行比较。

非视网膜

视网膜屏幕上的相同情况看起来不同。在这种情况下,一个点的大小是相同的,但它由 4 个像素而不是 1 个像素组成。这一次,当划线时,线上方的半点和线下方的半点将完全填满该行像素上面和下面因为更高分辨率的屏幕。这意味着线条看起来好像是 1 磅宽,并且颜色看起来完全不透明。

我们还可以看到填充的矩形看起来是一样的。

视网膜


要解决此问题,您可以将线的点放在半像素上。在低分辨率设备上从中心划线意味着该线向上延伸半个点,向下延伸半个点。由于线的中心现在位于点的中心,这意味着描边线完全位于像素内,并且线条看起来很清晰。这样做不会对视网膜线产生任何影响,因为向下(或向上)移动半个点,仍然意味着您完全填充了上方和下方的像素。

在下图中(对于视网膜),我同时显示了点网格和像素网格。

半像素非视网膜 半像素视网膜

于 2012-06-24T10:22:35.193 回答
2

使用描边和填充得到不同结果的原因是它们对参数的解释不同。

Stroke 在坐标的每一侧添加一半的线宽。所以,你的点是 20.0,线宽是 1px。理论上,结果将是 (19.5-20.5) 之间的 1 像素黑线。由于设备屏幕上没有任何非整数像素,它将在 (19-21) 之间转换为 2 像素灰色/模糊线。为了避免这种情况,您需要将每个坐标与 0.5 相加(如 CGPointMake(20.5, 10.5) ),这样宽度就不会再在像素之间划分。

但是,填充中的参数用于设置要填充的区域的边界,CGRectMake(40.0, 10.0, 1.0, 390.0) 表示 (40 - 41) 之间的区域。结果,没有小数部分落在像素上,看起来很模糊。

于 2014-04-24T08:40:19.597 回答