在UIView中绘制直线

90

我需要在UIView中画一条水平线。最简单的方法是什么?例如,我想要在y坐标为200处画一条黑色的水平线。

我不使用Interface Builder。


1
这是在所有iOS中正确拥有单像素线并在storyboard中轻松实现的完整简易解决方案:https://dev59.com/z4Tba4cB1Zd3GeqP7YYw#26525466 - Fattie
9个回答

314

也许有点晚了,但我想补充一下,有一种更好的方法。 使用UIView很简单,但相对较慢。这种方法覆盖了视图如何绘制自己,并且更快:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);

    // Draw them with a 2.0 stroke width so they are a bit more visible.
    CGContextSetLineWidth(context, 2.0f);

    CGContextMoveToPoint(context, 0.0f, 0.0f); //start at this point

    CGContextAddLineToPoint(context, 20.0f, 20.0f); //draw to this point

    // and now draw the Path!
    CGContextStrokePath(context);
}

38
用一个视图来实现并不太糟糕。例如,在方向变化期间执行隐式动画时,这会使事情变得更加容易。如果只有一个视图,再添加另一个UIView也并不会太昂贵,并且代码会更简单。 - i_am_jorf
1
此外,您可以使用以下代码获取边界和中点:CGPoint midPoint; midPoint.x = self.bounds.size.width / 2; midPoint.y = self.bounds.size.height / 2; - coolcool1994
@jeffamaphone 当使用自动布局时,如果通过约束来定义线条的长度或位置是最自然的方式,那么这也可能非常有用。 - Mark Amery
我做了这个,但当我调整视图大小时,线条会变形。 - jspooner
1
没错,说它“慢”是没有意义的。屏幕上有大量简单的UIView。请注意,绘制一个文本字符,以及所有相关的处理,会淹没绘制填充UIView所需的时间。 - Fattie
显示剩余3条评论

122

在您的情况下(水平线),最简单的方法是添加一个带有黑色背景颜色和框架[0,200,320,1]的子视图。

代码示例(我希望没有错误-我是在没有使用Xcode的情况下编写的):

UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
[lineView release];
// You might also keep a reference to this view 
// if you are about to change its coordinates.
// Just create a member and a property for this...

另一种方法是创建一个类,在其drawRect方法中画一条线(您可以在这里查看我的代码示例)。


不要在Storyboard中编写任何代码,这样更容易更好。 - coolcool1994
3
@coolcool1994,你有没有注意到问题中的“我不使用Interface Builder”的要求? - Michael Kessler

37

Swift 3 和 Swift 4

以下是如何在视图末尾绘制灰色线条的方法(与 b123400 的答案类似)

class CustomView: UIView {

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        if let context = UIGraphicsGetCurrentContext() {
            context.setStrokeColor(UIColor.gray.cgColor)
            context.setLineWidth(1)
            context.move(to: CGPoint(x: 0, y: bounds.height))
            context.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
            context.strokePath()
        }
    }
}

当从viewDidLayoutSubviews调用“if let context”时,它会失败。 - Oscar

15

只需添加一个没有文字但带有背景颜色的标签。 设置您选择的坐标、高度和宽度。 您可以手动添加,也可以使用界面生成器。


13

您可以使用UIBezierPath类来实现此功能:

并且可以绘制任意数量的线条:

我已经创建了一个UIView的子类:

    @interface MyLineDrawingView()
    {
       NSMutableArray *pathArray;
       NSMutableDictionary *dict_path;
       CGPoint startPoint, endPoint;
    }

       @property (nonatomic,retain)   UIBezierPath *myPath;
    @end

并初始化了将用于线条绘制的pathArray和dictPAth对象。我正在撰写自己项目的主要代码:

- (void)drawRect:(CGRect)rect
{

    for(NSDictionary *_pathDict in pathArray)
    {
        [((UIColor *)[_pathDict valueForKey:@"color"]) setStroke]; // this method will choose the color from the receiver color object (in this case this object is :strokeColor)
        [[_pathDict valueForKey:@"path"] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
    }

    [[dict_path objectForKey:@"color"] setStroke]; // this method will choose the color from the receiver color object (in this case this object is :strokeColor)
    [[dict_path objectForKey:@"path"] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];

}

touchesBegin方法:

UITouch *touch = [touches anyObject];
startPoint = [touch locationInView:self];
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth = currentSliderValue*2;
dict_path = [[NSMutableDictionary alloc] init];

touchesMoved 方法:

UITouch *touch = [touches anyObject];
endPoint = [touch locationInView:self];

 [myPath removeAllPoints];
        [dict_path removeAllObjects];// remove prev object in dict (this dict is used for current drawing, All past drawings are managed by pathArry)

    // actual drawing
    [myPath moveToPoint:startPoint];
    [myPath addLineToPoint:endPoint];

    [dict_path setValue:myPath forKey:@"path"];
    [dict_path setValue:strokeColor forKey:@"color"];

    //                NSDictionary *tempDict = [NSDictionary dictionaryWithDictionary:dict_path];
    //                [pathArray addObject:tempDict];
    //                [dict_path removeAllObjects];
    [self setNeedsDisplay];

touchesEnded 方法:

        NSDictionary *tempDict = [NSDictionary dictionaryWithDictionary:dict_path];
        [pathArray addObject:tempDict];
        [dict_path removeAllObjects];
        [self setNeedsDisplay];

12

还有一种可能性(甚至更短)。如果你在drawRect内部,可以尝试以下代码:

[[UIColor blackColor] setFill];
UIRectFill((CGRect){0,200,rect.size.width,1});

2

Swift 3, 4, 5

这是我能找到的最简单的...


这段文字涉及IT技术,介绍了Swift编程语言的版本3、4和5。
let lineView = UIView(frame: CGRect(x: 4, y: 50, width: self.view.frame.width, height: 1))
lineView.backgroundColor = .lightGray
self.view.addSubview(lineView)

1

根据Guy Daher的回答。

我尽量避免使用?,因为如果GetCurrentContext()返回nil,它可能会导致应用程序崩溃。

我会使用if语句进行nil检查:

class CustomView: UIView 
{    
    override func draw(_ rect: CGRect) 
    {
        super.draw(rect)
        if let context = UIGraphicsGetCurrentContext()
        {
            context.setStrokeColor(UIColor.gray.cgColor)
            context.setLineWidth(1)
            context.move(to: CGPoint(x: 0, y: bounds.height))
            context.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
            context.strokePath()
        }
    }
}

2
如果 if 语句的原因仅仅是为了从可选类型中取出值,建议使用 guard 语句。 - Julio Flores

-1
通过代码或者接口构建器添加没有文本并且背景颜色与框架大小相对应(例如:高度=1)的标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接