如何在iOS中绘制单点线

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

起初,我用的是1px的UIView,并用灰色着色。 但在视网膜显示看起来像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%的时间出于某种原因运作。是不是有问题? 无论如何,我很乐意听到更好的方法。

谢谢。

我做了一个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]; } 

只是为了增加雷米的伟大答案,这可能更简单。 创build一个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像素线,在那种颜色的宽度。 (你可能不应该受到故事板/ xib中任何默认的自动设置大小设置的影响,我不能让它中断。)你完成了。

注意:你可能会想“为什么不把UIView的代码调整到 awakeFromNib中?” 在加载故事板应用程序时调整视图大小是有问题的 – 请参阅这里的许多问题!

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


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

 shapeLayer.lineWidth = 0.5f; 

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

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

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

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

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

在这里输入图像说明

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

AutoLayout方法:

我使用普通的旧UIView,并在Interface Builder中将其高度约束设置为1。 通过限制附加到底部。 界面生成器不允许你设置高度约束为0.5,但你可以在代码中完成。

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

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

为我工作。

FWIW我不认为我们需要支持非视网膜屏幕了。 不过,我仍然使用主屏幕比例来validation应用程序。

你必须考虑到由于视网膜的缩放,你不是指屏幕像素。 请参阅核心graphics点与像素 。

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

 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 } }