Peres Peres - 6 months ago 38
iOS Question

UIView with a Dashed line

What I have:

enter image description here

To create this line, I basically have an

and I do the following:

void setLayerToLineFromAToB(CALayer *layer, CGPoint a, CGPoint b, CGFloat lineWidth)
CGPoint center = { 0.5 * (a.x + b.x), 0.5 * (a.y + b.y) };
CGFloat length = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
CGFloat angle = atan2(a.y - b.y, a.x - b.x);

layer.position = center;
layer.bounds = (CGRect) { {0, 0}, { length + lineWidth, lineWidth } };
layer.transform = CATransform3DMakeRotation(angle, 0, 0, 1);

Note: This code was found here on stackoverflow, so if someone can give me the reference to it I would appreciate.

What I want:

enter image description here

Ok so the "only" thing I need is to create this pattern on the
. I know I am able to do this using Quartz2D (a simple way to do it can be found here). But I want to do it by manipulating the
and not going to to the draw method. Why? Because of the transformation I am making on my
, I am not able to draw correctly using the

Edit 1:

Just to illustrate my problem:

enter image description here

Normally what you have is
and then you basically just draw something in it (in this case a simple line). The solution I found to get rid of the "gray" area, was to instead of drawing something, just transform the
itself. It work well, if you want a fully filled line, the problem comes when you want a dashed one.


Note: The code from Prince did really help me out, so I will give him +10 for the tips. But in the end, I add to come with my own code. I will also add some context to it, so it can be useful for future readers

The final code was like this:


      // Important, otherwise we will be adding multiple sub layers
      if ([[[self layer] sublayers] objectAtIndex:0])
            self.layer.sublayers = nil;

        CAShapeLayer *shapeLayer = [CAShapeLayer layer];
        [shapeLayer setBounds:self.bounds];
        [shapeLayer setFillColor:[[UIColor clearColor] CGColor]];
        [shapeLayer setStrokeColor:[[UIColor blackColor] CGColor]];
        [shapeLayer setLineWidth:3.0f];
        [shapeLayer setLineJoin:kCALineJoinRound];
        [shapeLayer setLineDashPattern:
        [NSArray arrayWithObjects:[NSNumber numberWithInt:10],
        [NSNumber numberWithInt:5],nil]];

        // Setup the path
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL,,;
        CGPathAddLineToPoint(path, NULL,,;

        [shapeLayer setPath:path];

        [[self layer] addSublayer:shapeLayer];

In my case, the beginPoint and endPoint are movable by the user, by using KVO. So when one of them moves:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    if ([keyPath isEqual:@"position"])
        [self updateLine];

I did play a lot with Prince's code. I tried on the draw: method, which add a thin line between the dashed line (a bit weird...) and I also tried on initWithFrame:. By itself his code, without any modifications, would give me this kind of errors on the console:

<Error>: CGContextSaveGState: invalid context 0x0
<Error>: CGContextSetLineWidth: invalid context 0x0
<Error>: CGContextSetLineJoin: invalid context 0x0
<Error>: CGContextSetLineCap: invalid context 0x0
<Error>: CGContextSetMiterLimit: invalid context 0x0
<Error>: CGContextSetFlatness: invalid context 0x0
<Error>: CGContextAddPath: invalid context 0x0
<Error>: CGContextDrawPath: invalid context 0x0
<Error>: CGContextRestoreGState: invalid context 0x0