如何在iOS中绘制单点线

时间:2014-03-27 16:24:46

标签: ios uitableview retina-display

我想知道绘制单点线的最佳方法是什么? 我的目标是在tableViewCell中绘制这一行,使其看起来就像本机单元格分隔符。 我不想使用原生分隔符,因为我想制作不同的颜色和不同的位置(不是底部..)。

起初我使用1px UIView并将其涂成灰色。但在Retina显示器中它看起来像2px。 也尝试使用这种方法:

- (void)drawLine:(CGPoint)startPoint endPoint:(CGPoint)endPoint inColor:(UIColor *)color {

    CGMutablePathRef straightLinePath = CGPathCreateMutable();
    CGPathMoveToPoint(straightLinePath, NULL, startPoint.x, startPoint.y);
    CGPathAddLineToPoint(straightLinePath, NULL, endPoint.x, endPoint.y);

    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = straightLinePath;
    UIColor *fillColor = color;
    shapeLayer.fillColor = fillColor.CGColor;
    UIColor *strokeColor = color;
    shapeLayer.strokeColor = strokeColor.CGColor;
    shapeLayer.lineWidth = 0.5f;
    shapeLayer.fillRule = kCAFillRuleNonZero;
    [self.layer addSublayer:shapeLayer];
}

由于某种原因,它在60%的时间内起作用..它有什么问题吗? 无论如何,我很高兴听到更好的方式。

感谢。

5 个答案:

答案 0 :(得分:17)

我对UIView类别做了同样的事情。以下是我的方法:

#define SEPARATOR_HEIGHT 0.5

- (void)addSeparatorLinesWithColor:(UIColor *)color
{
    [self addSeparatorLinesWithColor:color edgeInset:UIEdgeInsetsZero];
}


- (void)addSeparatorLinesWithColor:(UIColor *)color edgeInset:(UIEdgeInsets)edgeInset
{

    UIView *topSeparatorView = [[UIView alloc] initWithFrame:CGRectMake(edgeInset.left, - SEPARATOR_HEIGHT, self.frame.size.width - edgeInset.left - edgeInset.right, SEPARATOR_HEIGHT)];
    [topSeparatorView setBackgroundColor:color];
    [self addSubview:topSeparatorView];

    UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(edgeInset.left, self.frame.size.height + SEPARATOR_HEIGHT, self.frame.size.width - edgeInset.left - edgeInset.right, SEPARATOR_HEIGHT)];
    [separatorView setBackgroundColor:color];
    [self addSubview:separatorView];
}

只是为了增加Rémy的好答案,这可能更简单。上课UILine.m

@interface UILine:UIView
@end
@implementation UILine
-(id)awakeFromNib
    {
    // careful, contentScaleFactor does NOT WORK in storyboard during initWithCoder.
    // example, float sortaPixel = 1.0/self.contentScaleFactor ... does not work.
    // instead, use mainScreen scale which works perfectly:
    float sortaPixel = 1.0/[UIScreen mainScreen].scale;
    UIView *topSeparatorView = [[UIView alloc] initWithFrame:
        CGRectMake(0, 0, self.frame.size.width, sortaPixel)];

    topSeparatorView.userInteractionEnabled = NO;
    [topSeparatorView setBackgroundColor:self.backgroundColor];
    [self addSubview:topSeparatorView];

    self.backgroundColor = [UIColor clearColor];
    self.userInteractionEnabled = NO;
    }
@end

在IB中,放入UIView,单击身份检查器并将该类重命名为UILine。在IB中设置所需的宽度。将高度设置为1或2像素 - 这样您就可以在IB中看到它。在IB中设置所需的背景颜色。当您运行应用程序时,它将成为1像素线,即该颜色的宽度。 (你可能不应该受到storyboard / xib中任何默认自动调整大小设置的影响,我无法让它破裂。)你已经完成了。

注意:您可能会想“为什么不在awakeFromNib中的调整UIView 的大小?”在故事板应用程序中加载视图时加载视图是有问题的 - 请参阅此处的许多问题!

有趣的gotchya :你可能只是在故事板上制作UIView,比如10或20像素高,这样你就可以看到它。当然它在应用程序中消失了,你得到了漂亮的一个像素线。但!一定要记住self.userInteractionEnabled = NO,否则它可能会超过你的其他按钮!


2016解决方案! https://stackoverflow.com/a/34766567/294884

答案 1 :(得分:2)

shapeLayer.lineWidth = 0.5f;

这是一个常见的错误,也是这种情况仅在某些时候起作用的原因。有时这会完全重叠屏幕上的像素,有时它会赢。绘制始终有效的单点线的方法是在整数边界上绘制一个点厚的矩形,然后填充它。这样,它将始终完全匹配屏幕上的像素。

要从点转换为像素,如果您想这样做,请使用视图的比例因子。

因此,这将始终是一个像素宽:

CGContextFillRect(con, CGRectMake(0,0,desiredLength,1.0/self.contentScaleFactor));

这是一个屏幕截图,显示用作分隔符的行,绘制在每个单元格的顶部:

enter image description here

表视图本身没有分隔符(如三个现有单元格下方的空白区域所示)。我可能不会在你想要的位置,长度和颜色上划清界限,但那是你的关注,而不是我的。

答案 2 :(得分:2)

AutoLayout方法:

我使用普通的旧UIView并在Interface Builder中将其高度约束设置为1。通过约束将其附加到底部。界面构建器不允许您将高度约束设置为0.5,但您可以在代码中执行此操作。

为高度约束创建一个连接器,然后调用它:

// Note: This will be 0.5 on retina screens
self.dividerViewHeightConstraint.constant =  1.0/[UIScreen mainScreen].scale 

为我工作。

FWIW我认为我们不再需要支持非视网膜屏幕了。但是,我仍然使用主屏幕比例来证明应用程序的未来。

答案 3 :(得分:1)

您必须考虑视网膜引起的缩放,并且您不是指屏幕像素。请参阅Core Graphics Points vs. Pixels

答案 4 :(得分:0)

除了RémyVirin的回答,使用Swift 3.0 创建LineSeparator类:

import UIKit

class LineSeparator: UIView {

override func awakeFromNib() {

    let sortaPixel: CGFloat = 1.0/UIScreen.main.scale

    let topSeparatorView = UIView()
    topSeparatorView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: sortaPixel)

    topSeparatorView.isUserInteractionEnabled = false
    topSeparatorView.backgroundColor = self.backgroundColor

    self.addSubview(topSeparatorView)
    self.backgroundColor = UIColor.clear

    self.isUserInteractionEnabled = false   
    }
}