12

我想用 2 种不同颜色的 1px 线绘制双色线。我有很多代码,所以我在尝试解释后将其放入。

如果我使用 uiviewdrawRect方法,当我关闭抗锯齿时它可以正常工作,但是当我使用图层时drawLayerInContext,它要么显示一条普通线,要么显示一条 2px 的普通线,关闭抗锯齿,或者显示两条 2px 的半透明线,开启抗锯齿。

通过创建具有自定义上下文的图像,我设法获得了与 UIView 的 drawRect 方法类似的行为,我可以在其中指定比例:

UIGraphicsBeginImageContextWithOptions([self bounds].size, NO, 0.f); // 0.f for scale means "scale for device's main screen".

我只想知道为什么我没有得到相同的行为,drawInContext以及是否有办法获得类似的行为。

这是绘制双色线的代码:

void DRAW_DOUBLE_LINE(CGContextRef ctx, CGPoint startPoint, CGPoint endPoint, UIColor* topColor, UIColor* bottomColor)
{
    UIGraphicsPushContext(ctx);

    UIBezierPath *topLine = [[UIBezierPath alloc] init];
    CGPoint topLineStartPoint = startPoint;
    CGPoint topLineEndPoint = endPoint;
    [topLine moveToPoint:topLineStartPoint];
    [topLine addLineToPoint:topLineEndPoint];
    [topColor setStroke];
    topLine.lineWidth = 0.5;
    [topLine stroke];

    UIBezierPath *bottomLine = [[UIBezierPath alloc] init];
    CGPoint bottomLineStartPoint = topLineStartPoint;
    bottomLineStartPoint.y +=0.5;
    CGPoint bottomLineEndPoint = topLineEndPoint;
    bottomLineEndPoint.y +=0.5;
    [bottomLine moveToPoint:bottomLineStartPoint];
    [bottomLine addLineToPoint:bottomLineEndPoint];
    [bottomColor setStroke];
    bottomLine.lineWidth = 0.5;
    [bottomLine stroke];

    UIGraphicsPopContext();
}

用我的drawRect方法UIView得到这个:

| 点y坐标| 抗锯齿 | 结果 |
| ------------------- | ------------ | ------------------------------------------- |
| 5 | 否 | 2 行 1 像素:宾果游戏!|
| 5.25 | 否 | 2 行 1 像素:宾果游戏!|
| 5.5 | 否 | 2 行 1 像素:宾果游戏!|
| 5 | 是 | 1px的3条半透明线|
| 5.25 | 是 | 2 行 1 像素:宾果游戏!|
| 5.5 | 是 | 1px的3条半透明线|

在带有 drawInContext 的 CALayer 中,我得到了这些结果

| 点y坐标| 抗锯齿 | 结果 |
| ------------------- | ------------ | ------------------------------------------- |
| 5 | 否 | 2 行 2 像素 |
| 5.25 | 否 | 1 行 2 像素 |
| 5.5 | 否 | 1 行 2 像素 |
| 5 | 是 | 2px的2条半透明线|
| 5.25 | 是 | 1条2px的半透明线|
| 5.5 | 是 | 2px的2条半透明线|

使用我的自定义上下文,我得到了这个:

| 点y坐标| 抗锯齿 | 结果 |
| ------------------- | ------------ | ------------------------------------------- |
| 5 | 否 | 2 行 1 像素:宾果游戏!|
| 5.25 | 否 | 2 行 1 像素:宾果游戏!|
| 5.5 | 否 | 2 行 1 像素:宾果游戏!|
| 5 | 是 | 1px的3条半透明线|
| 5.25 | 是 | 2 行 1 像素:宾果游戏!|
| 5.5 | 是 | 1px的3条半透明线|

实现代码drawRect

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGPoint startPoint = CGPointMake(0, 5);
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds),5);

    UIColor* topLineColor = [UIColor whiteColor];
    UIColor* bottomLineColor = [UIColor blackColor];

    DRAW_DOUBLE_LINE(context, startPoint, endPoint, topLineColor, bottomLineColor);
}

实现代码drawInContext

-(void)drawInContext:(CGContextRef)ctx{
    CGPoint startPoint = CGPointMake(0, 5);
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds),5);

    UIColor* topLineColor = [UIColor whiteColor];
    UIColor* bottomLineColor = [UIColor blackColor];

    DRAW_DOUBLE_LINE(ctx, startPoint, endPoint, topLineColor, bottomLineColor);
}

CALayer方法中自定义上下文实现代码display

-(void)display{

    if ([UIScreen instancesRespondToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions([self bounds].size, NO, 0.f); // 0.f for scale means "scale for device's main screen".
    } else {
        UIGraphicsBeginImageContext([self bounds].size);
    }

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGPoint startPoint = CGPointMake(0, 5.25);
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds),5.25);
    UIColor* topLineColor = [UIColor whiteColor];
    UIColor* bottomLineColor = [UIColor blackColor];

    DRAW_DOUBLE_LINE(ctx, startPoint, endPoint, topLineColor, bottomLineColor);

    UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    self.contents = (id)coloredImg.CGImage;
}
4

4 回答 4

1

不要使用 0.5 作为宽度。

替换0.51.0 / [UIScreen mainScreen].scale

当您在图层上绘制时,您可以获得 1 像素宽度的线。

于 2015-07-07T09:44:48.420 回答
0

我建议不要画线,而是画出所需大小的填充矩形。具有不同分辨率的棘手部分之一是线的起点和终点的位置。但是绘制矩形要容易得多。

矩形的坐标始终是偶数,因为您的目标是边缘而不是像素的中心。

于 2014-03-07T14:32:55.970 回答
0

绘制和填充矩形而不是线条。矩形的坐标应始终位于像素的边缘而不是中心。

于 2015-06-24T18:10:42.490 回答
0

我发现在视网膜/非视网膜上获得精确/清晰的 1px 线条并将它们保持为 1px 的最佳方法是编写着色器,即使您放大也是如此。就我而言,我使用的是 OpenGL,但我相信你可以使用 Metal for CALayers 来做到这一点。基本过程是绘制一个高度为零的矩形(如果线条是垂直的,则为零宽度),然后在着色器中将这些点向外推所需的像素数。

我从这里得到了这个想法:https ://www.mapbox.com/blog/drawing-antialiased-lines/

于 2015-08-07T00:32:18.207 回答