4

I'm creating a dotted line from a UIBezierPath which looks like this:

Dotted line

This is the code I use to construct and draw the path:

const CGContextRef context = UIGraphicsGetCurrentContext();

const CGSize visibleSize = CGSizeMake(self.width - (kIndent * 2), self.height - (kIndent * 2));
UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(kIndent, kIndent, visibleSize.width, visibleSize.height) cornerRadius:kCornerRadius];
CGContextSetStrokeColorWithColor(context, [UIColor colorWithWhite:1.0 alpha:0.5].CGColor);
[borderPath setLineWidth:2.0];
[borderPath setLineCapStyle:kCGLineCapRound];

const CGFloat pattern[] = {6, 6};
[borderPath setLineDash:pattern count:2 phase:0];

[borderPath stroke];

What I want is for each corner of my square to have the exact same curvatures as each other. I know this will ultimately be determined by my pattern values. I have tried calculating different values from the width of the shape (the width changes with screen width), but I can't get my desired look.

Has anyone done this before, or have any ideas to share about how I'd do this?

Ricky
  • 3,101
  • 1
  • 25
  • 33

3 Answers3

1

This is what I done before. Not perfect but I think this can help you.

 - (void)tailorRect:(CGRect)aRect dotsWidth:(CGFloat)dotWidth radius:(CGFloat)radius withColor:(UIColor*)color{

    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextSaveGState(c);

    CGFloat minSpacing = 10;
    CGFloat mWidth  = aRect.size.width  - radius *2;
    CGFloat mHeight = aRect.size.height - radius *2;

    int countW = mWidth  / (dotWidth + minSpacing);
    int countH = mHeight / (dotWidth + minSpacing);

    CGFloat spacingW = (mWidth - (dotWidth * countW)) / (countW + 1);
    CGFloat spacingH = (mHeight -(dotWidth * countH)) / (countH + 1);

    CGContextSetLineCap(c, kCGLineCapRound);
    CGContextSetLineWidth(c, 1.2);

    CGRect tempRect = aRect;
    for (int r = 0; r<=1; r++)
    {
        if (r==0)
        {
            CGContextSetStrokeColorWithColor(c, [[UIColor whiteColor] colorWithAlphaComponent:0.9].CGColor);
            aRect = CGRectOffset(tempRect, 0, 0.5);
        }
        else
        {
            CGContextSetStrokeColorWithColor(c, color.CGColor);
            aRect = tempRect;
        }


        for (int w = 0; w<=1; w++)
        {
            CGFloat y = (w==0) ? aRect.origin.y : CGRectGetMaxY(aRect);
            CGPoint pointsW[countW*2];
            for (int i = 0; i<countW*2; i++)
            {
                CGFloat x;
                CGFloat startPointX = radius + spacingW +aRect.origin.x;

                if (i%2 != 0)
                {
                    x = startPointX
                    + dotWidth * (i+1)/     2
                    + spacingW * ((int)i/2);
                }
                else
                {
                    x = startPointX
                    + (dotWidth+spacingW) * ((int)i/2);
                }

                pointsW[i] = CGPointMake(x, y);
            }


            CGContextStrokeLineSegments(c, pointsW, countW*2);
        }

        for (int h = 0; h<=1; h++)
        {
            CGFloat x = (h==0) ? aRect.origin.x : CGRectGetMaxX(aRect);
            CGPoint pointsH[countH*2];
            for (int j = 0; j<countH*2; j++)
            {
                CGFloat startY = radius + spacingH + aRect.origin.y;
                CGFloat y;
                if (j%2 != 0)
                {
                    y = startY + dotWidth * (j+1)/2 + spacingH * ((int)j/2);
                }
                else
                {
                    y = startY + (dotWidth + spacingH) * ((int)j/2);
                }

                pointsH[j] = CGPointMake(x, y);
            }
            CGContextStrokeLineSegments(c, pointsH, countH*2);
        }

        //radius
        for (int i = 0; i<4; i++)
        {
            CGPoint point0;
            CGPoint point1;
            CGPoint point2;
            switch (i) {
                case 0:
                    point0 = CGPointMake(CGRectGetMinX(aRect), CGRectGetMinY(aRect) + radius);
                    point1 = CGPointMake(CGRectGetMinX(aRect), CGRectGetMinY(aRect));
                    point2 = CGPointMake(CGRectGetMinX(aRect) + radius, CGRectGetMinY(aRect));

                    break;
                case 1:
                    point0 = CGPointMake(CGRectGetMaxX(aRect) - radius, CGRectGetMinY(aRect));
                    point1 = CGPointMake(CGRectGetMaxX(aRect), CGRectGetMinY(aRect));
                    point2 = CGPointMake(CGRectGetMaxX(aRect) , CGRectGetMinY(aRect) +radius);
                    break;
                case 2:
                    point0 = CGPointMake(CGRectGetMaxX(aRect), CGRectGetMaxY(aRect) - radius);
                    point1 = CGPointMake(CGRectGetMaxX(aRect), CGRectGetMaxY(aRect));
                    point2 = CGPointMake(CGRectGetMaxX(aRect) - radius, CGRectGetMaxY(aRect));

                    break;
                case 3:
                    point0 = CGPointMake(CGRectGetMinX(aRect), CGRectGetMaxY(aRect) - radius);
                    point1 = CGPointMake(CGRectGetMinX(aRect), CGRectGetMaxY(aRect));
                    point2 = CGPointMake(CGRectGetMinX(aRect) + radius, CGRectGetMaxY(aRect));

                    break;

                default:
                    break;

            }

            CGContextMoveToPoint(c, point0.x, point0.y);
            CGContextAddArcToPoint(c, point1.x, point1.y, point2.x, point2.y, radius);
            CGContextStrokePath(c);

        }

    }

    CGContextRestoreGState(c);


}
PowHu
  • 2,159
  • 16
  • 17
1

It's very simple:

[yourView.layer setBorderWidth:5.0];
[yourView.layer setBorderColor:[[UIColor colorWithPatternImage:[UIImage imageNamed:@"DotedImage.png"]] CGColor]];///just add image name and create image with dashed or doted drawing and add here

Here you're just required to add QuartzCore/QuartzCore.h framework in project and import it as below in .m file

#import <QuartzCore/QuartzCore.h>

Or try using

- (void)drawDashedBorderAroundView:(UIView *)v
{
        //border definitions
    CGFloat cornerRadius = 10;
    CGFloat borderWidth = 2;
    NSInteger dashPattern1 = 8;
    NSInteger dashPattern2 = 8;
    UIColor *lineColor = [UIColor orangeColor];

        //drawing
    CGRect frame = v.bounds;

    CAShapeLayer *_shapeLayer = [CAShapeLayer layer];

        //creating a path
    CGMutablePathRef path = CGPathCreateMutable();

        //drawing a border around a view
    CGPathMoveToPoint(path, NULL, 0, frame.size.height - cornerRadius);
    CGPathAddLineToPoint(path, NULL, 0, cornerRadius);
    CGPathAddArc(path, NULL, cornerRadius, cornerRadius, cornerRadius, M_PI, -M_PI_2, NO);
    CGPathAddLineToPoint(path, NULL, frame.size.width - cornerRadius, 0);
    CGPathAddArc(path, NULL, frame.size.width - cornerRadius, cornerRadius, cornerRadius, -M_PI_2, 0, NO);
    CGPathAddLineToPoint(path, NULL, frame.size.width, frame.size.height - cornerRadius);
    CGPathAddArc(path, NULL, frame.size.width - cornerRadius, frame.size.height - cornerRadius, cornerRadius, 0, M_PI_2, NO);
    CGPathAddLineToPoint(path, NULL, cornerRadius, frame.size.height);
    CGPathAddArc(path, NULL, cornerRadius, frame.size.height - cornerRadius, cornerRadius, M_PI_2, M_PI, NO);

        //path is set as the _shapeLayer object's path
    _shapeLayer.path = path;
    CGPathRelease(path);

    _shapeLayer.backgroundColor = [[UIColor clearColor] CGColor];
    _shapeLayer.frame = frame;
    _shapeLayer.masksToBounds = NO;
    [_shapeLayer setValue:[NSNumber numberWithBool:NO] forKey:@"isCircle"];
    _shapeLayer.fillColor = [[UIColor clearColor] CGColor];
    _shapeLayer.strokeColor = [lineColor CGColor];
    _shapeLayer.lineWidth = borderWidth;
    _shapeLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:dashPattern1], [NSNumber numberWithInt:dashPattern2], nil];
    _shapeLayer.lineCap = kCALineCapRound;

        //_shapeLayer is added as a sublayer of the view, the border is visible
    [v.layer addSublayer:_shapeLayer];
    v.layer.cornerRadius = cornerRadius;
}

You can have some study in

http://lukagabric.com/cashapelayer-example-round-corners-view-with-dashed-line-border/

https://github.com/lukagabric/LBorderView

drawing dashed line using CALayer

UIView with a Dashed line

Community
  • 1
  • 1
Nischal Hada
  • 3,230
  • 3
  • 27
  • 57
1

Here is a UIView subclass that can work for any project, it also works for round views:

import UIKit

class CustomDashedView: UIView {

@IBInspectable var cornerRadius: CGFloat = 0 {
    didSet {
        layer.cornerRadius = cornerRadius
        layer.masksToBounds = cornerRadius > 0
    }
}
@IBInspectable var dashWidth: CGFloat = 0
@IBInspectable var dashColor: UIColor = .clear
@IBInspectable var dashLength: CGFloat = 0
@IBInspectable var betweenDashesSpace: CGFloat = 0

var dashBorder: CAShapeLayer?

override func layoutSubviews() {
    super.layoutSubviews()
    dashBorder?.removeFromSuperlayer()
    let dashBorder = CAShapeLayer()
    dashBorder.lineWidth = dashWidth
    dashBorder.strokeColor = dashColor.cgColor
    dashBorder.lineDashPattern = [dashLength, betweenDashesSpace] as [NSNumber]
    dashBorder.frame = bounds
    dashBorder.fillColor = nil
    if cornerRadius > 0 {
        dashBorder.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath
    } else {
        dashBorder.path = UIBezierPath(rect: bounds).cgPath
    }
    layer.addSublayer(dashBorder)
    self.dashBorder = dashBorder
}

}

This way you can edit from the Storyboard like this:

enter image description here

Poornima Mishra
  • 406
  • 2
  • 18