89

I need to draw a horizontal line in a UIView. What is the easiest way to do it. For example, I want to draw a black horizontal line at y-coord=200.

I am NOT using Interface Builder.

1
  • 1
    Here's the complete & easy solution to correctly having a single-pixel line, in all iOS, and making it easy in storyboard: stackoverflow.com/a/26525466/294884 Commented Oct 23, 2014 at 12:05

9 Answers 9

311

Maybe this is a bit late, but I want to add that there is a better way. Using UIView is simple, but relatively slow. This method overrides how the view draws itself and is faster:

- (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); } 
Sign up to request clarification or add additional context in comments.

8 Comments

If this code is used in a UIView are the coordinates in this sample relative to the bounds of the view or the entire screen?
Does one not need to call CGContextBeginPath(context); before CGContextMoveToPoint(...);?
Using a view to do it isn't too horrible. It makes things easier, for example, when doing implicit animations during orientation changes. If it's just one, another UIView isn't all that expensive and the code is much simpler.
In addition, you can get bounds and midpoint with these codes: CGPoint midPoint; midPoint.x = self.bounds.size.width / 2; midPoint.y = self.bounds.size.height / 2;
Right, the comment that it is "slow" is not sensible. There are huge numbers of simple UIViews on screen at any time. Note that drawing ONE (!) text character, with all the processing that involves, swamps drawing a filled UIView.
|
122

The easiest way in your case (horizontal line) is to add a subview with black background color and frame [0, 200, 320, 1].

Code sample (I hope there are no errors - I wrote it without 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... 

Another way is to create a class that will draw a line in its drawRect method (you can see my code sample for this here).

2 Comments

Do this without any code in Storyboard. It's easier and better.
@coolcool1994, haven't you noticed "I am NOT using Interface Builder." requirement in the question?
37

Swift 3 and Swift 4

This is how you can draw a gray line at the end of your view (same idea as b123400's answer)

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

3 Comments

The "if let context" fails when called from viewDidLayoutSubviews.
@Oscar , you NEVER call functions like draw#rect - they are called by the system (that's why it is an override).
@Fattie I didn't post that as a solution. I just noted that the call fails.
15

Just add a Label without text and with background color. Set the Coordinates of your choice and also height and width. You can do it manually or with Interface Builder.

Comments

13

You can user UIBezierPath Class for this:

And can draw as many lines as you want:

I have subclassed UIView :

 @interface MyLineDrawingView() { NSMutableArray *pathArray; NSMutableDictionary *dict_path; CGPoint startPoint, endPoint; } @property (nonatomic,retain) UIBezierPath *myPath; @end 

And initialized the pathArray and dictPAth objects which will be used for line drawing. I am writing the main portion of the code from my own project:

- (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 method :

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

touchesMoved Method:

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 Method:

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

Comments

12

One other (and an even shorter) possibility. If you're inside drawRect, something like the following:

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

Comments

3

Swift 3, 4, 5

This is the simplest of all I could find...

let lineView = UIView(frame: CGRect(x: 4, y: 50, width: self.view.frame.width, height: 1)) lineView.backgroundColor = .lightGray self.view.addSubview(lineView) 

Comments

1

Based on Guy Daher's answer.

I try to avoid using ? because it can cause an application crash if the GetCurrentContext() returns nil.

I would do nil check if statement:

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

1 Comment

if the reason for the if clause is just to unbox from the optional, prefer to use a guard statement instead.
-1

Add label without text and with background color corresponding frame size(ex:height=1). Do it through code or in interface builder.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.