Search code examples
iosobjective-cuiviewuitouch

Draw a 5 pixel line on UIView


I have a very simple (well hopefully very simple) question. In Objective-C, how do you draw a line between two points and add it to a UIView? I have tried using a UIImageView and manipulating its Transform property, but that ends up turning the line into a square or a rectangle when using the following code:

[[self tline] setFrame:CGRectMake(start.x, start.y, width, 5)];
[[self tline] setTransform:CGAffineTransformMakeRotation(angle)];

I have two CGPoints, start and end, and I would like to draw a dynamic 5px line between the two points and add it to my subview.

BK:

The point start is the point where the user begins touching the screen, and the point end is the point where the user's finger is currently. Obviously this will move a lot during gameplay. I need to be able to move this line to connect these two points.

I am using the touchesBegan:, Moved:, and Ended: methods to create, move, and destroy the line.

CoreGraphics

I have the following code; how do I add this line to self.view?

CGContextRef c = UIGraphicsGetCurrentContext();
CGFloat color[4] = {1.0f, 1.0f, 1.0f, 0.6f};
CGContextSetStrokeColor(c, color);
CGContextBeginPath(c);
CGContextMoveToPoint(c, start.x, start.y);
CGContextAddLineToPoint(c, end.x, end.y);
CGContextSetLineWidth(c, 5);
CGContextSetLineCap(c, kCGLineCapRound);
CGContextStrokePath(c);

Custom UIView:

#import <UIKit/UIKit.h>

@interface DrawingView : UIView

@property (nonatomic) CGPoint start;
@property (nonatomic) CGPoint end;

- (void)drawRect:(CGRect)rect;

@end

#import "DrawingView.h"

@implementation DrawingView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextSetLineCap(context, kCGLineCapSquare);
    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor); //change color here
    CGFloat lineWidth = 5.0; //change line width here
    CGContextSetLineWidth(context, lineWidth);
    CGPoint startPoint = [self start];
    CGPoint endPoint = [self end];
    CGContextMoveToPoint(context, startPoint.x + lineWidth/2, startPoint.y + lineWidth/2);
    CGContextAddLineToPoint(context, endPoint.x + lineWidth/2, endPoint.y + lineWidth/2);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);

    NSLog(@"%f",_end.x);
}

- (void)setEnd:(CGPoint)end
{
    _end = end;
    [self setNeedsDisplay];
}

@end

drawRect: is only called when I initialize the view...

Draw method in UIViewController:

- (void)drawTLine:(CGPoint)start withEndPoint:(CGPoint)end
{   
    [[self dview] setStart:start];
    [[self dview] setEnd:end];
    [[self dview] drawRect:[self dview].frame];
}

This is how I add the drawing view:

DrawingView* dview = [[DrawingView alloc] initWithFrame:self.view.frame];
[dview setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:dview];

Solution

  • Subclass UIView and perform custom drawing using the drawRect: method

    - (void)drawRect:(CGRect)rect {
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSaveGState(context);
        CGContextSetLineCap(context, kCGLineCapSquare);
        CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor); //change color here
        CGFloat lineWidth = 1.0; //change line width here
        CGContextSetLineWidth(context, lineWidth); 
        CGPoint startPoint = rect.origin; //change start point here
        CGPoint endPoint = {.x = CGRectGetMaxX(rect), .y = startPoint.y} //change end point here
        CGContextMoveToPoint(context, startPoint.x + lineWidth/2, startPoint.y + lineWidth/2);
        CGContextAddLineToPoint(context, endPoint.x + lineWidth/2, endPoint.y + lineWidth/2);
        CGContextStrokePath(context);
        CGContextRestoreGState(context);        
    }
    

    This will draw a black 1px line at the top of your UIView.

    If you need to update the line you can just use some properties like

    @property (nonatomic) CGPoint startPoint;
    

    and provide a custom implementation for the setter like

    - (void)setStartPoint:(CGPoint)point {
          _point = point;
          [self setNeedsDisplay]; // this will cause drawRect: to be called again
    }
    

    Do that for every property that you wish to control and make your drawRect: use such properties for drawing.