How to make a dashed line in swift?
Asked Answered
E

8

42

I want to know how to make a dashed line in swift like this: - - - - - - - - instead of a regular straight line like this: ----------------, I know that i can make multiple lines but that will require so much unnecessary code if i can just write it in 1 line. Btw it has to be in CoreGraphics.

Embrocation answered 15/8, 2016 at 19:13 Comment(3)
Can you show your current line creation code?Operand
Lookup CGContextSetLineDash.Rothstein
Please try this: stackoverflow.com/questions/78365576/custom-dashed-border-viewNorris
B
40

You create Dashed Lines the same way as Objective-C, except that you'll use Swift.

Here is how you do it using UIBezierPath:

let  path = UIBezierPath()

let  p0 = CGPoint(x: self.bounds.minX, y: self.bounds.midY)
path.move(to: p0)

let  p1 = CGPoint(x: self.bounds.maxX, y: self.bounds.midY)
path.addLine(to: p1)

let  dashes: [ CGFloat ] = [ 16.0, 32.0 ]
path.setLineDash(dashes, count: dashes.count, phase: 0.0)

path.lineWidth = 8.0
path.lineCapStyle = .butt
UIColor.magenta.set()
path.stroke()

Here is how to draw Dotted Lines using UIBezierPath:

let  path = UIBezierPath()

let  p0 = CGPointMake(CGRectGetMinX(self.bounds), CGRectGetMidY(self.bounds))
path.moveToPoint(p0)

let  p1 = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMidY(self.bounds))
path.addLineToPoint(p1)

let  dashes: [ CGFloat ] = [ 0.0, 16.0 ]
path.setLineDash(dashes, count: dashes.count, phase: 0.0)
path.lineWidth = 8.0
path.lineCapStyle = .Round
UIColor.magentaColor().set()
path.stroke()

Here is how to draw Dashed Lines Using CGContext:

let  context: CGContext = UIGraphicsGetCurrentContext()!

let  p0 = CGPointMake(CGRectGetMinX(self.bounds), CGRectGetMidY(self.bounds))
CGContextMoveToPoint(context, p0.x, p0.y)

let  p1 = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMidY(self.bounds))
CGContextAddLineToPoint(context, p1.x, p1.y)

let  dashes: [ CGFloat ] = [ 16.0, 32.0 ]
CGContextSetLineDash(context, 0.0, dashes, dashes.count)

CGContextSetLineWidth(context, 8.0)
CGContextSetLineCap(context, .Butt)
UIColor.blueColor().set()
CGContextStrokePath(context)
Beseech answered 16/8, 2016 at 18:57 Comment(1)
Line not coming when I am passing two buttons bound as parameter, How to draw dotted line between two UIbutton. here is my code let path = UIBezierPath() let p0 = CGPointMake(CGRectGetMinX(self.button1.bounds), CGRectGetMidY(self.button1.bounds)) path.moveToPoint(p0) let p1 = CGPointMake(CGRectGetMaxX(self.button2.bounds), CGRectGetMidY(self.button2.bounds)) path.addLineToPoint(p1)Tricolor
G
78

Swift 4

@IBOutlet var dashedView: UIView!

func drawDottedLine(start p0: CGPoint, end p1: CGPoint, view: UIView) {
    let shapeLayer = CAShapeLayer()
    shapeLayer.strokeColor = UIColor.lightGray.cgColor
    shapeLayer.lineWidth = 1
    shapeLayer.lineDashPattern = [7, 3] // 7 is the length of dash, 3 is length of the gap.

    let path = CGMutablePath()
    path.addLines(between: [p0, p1])
    shapeLayer.path = path
    view.layer.addSublayer(shapeLayer)
}

Call function

drawDottedLine(start: CGPoint(x: dashedView.bounds.minX, y: dashedView.bounds.minY), end: CGPoint(x: dashedView.bounds.maxX, y: dashedView.bounds.minY), view: dashedView)

With the above you will have a straight line, you can also change points as you wish, for example if you change the end point's y from dashedView.bounds.minY to dashedView.bounds.maxY you will have diagonal.

If you will use it in a subclass of UIView you won't have the outlet so you will use it with self instead.

Garniture answered 15/3, 2018 at 16:57 Comment(5)
Here layer not difinedScarcely
Hi @VineeshTP, the layer is from "view.layer" the view which you wish to add the dashed-line.Garniture
If we have selected iphone 8 in storyboard and then, if we apply this code and run it on iPhone 5s, then dashed line goes beyond the width.Gustative
The start and end point of the dashed line is attached to the view, so please make sure your view doesn't go over the bounds in iPhone 5s.Garniture
You must also make the dashedView background .clear if you want the non-dotted line to disappear if you drew that with constraints in the storyboardGuess
B
40

You create Dashed Lines the same way as Objective-C, except that you'll use Swift.

Here is how you do it using UIBezierPath:

let  path = UIBezierPath()

let  p0 = CGPoint(x: self.bounds.minX, y: self.bounds.midY)
path.move(to: p0)

let  p1 = CGPoint(x: self.bounds.maxX, y: self.bounds.midY)
path.addLine(to: p1)

let  dashes: [ CGFloat ] = [ 16.0, 32.0 ]
path.setLineDash(dashes, count: dashes.count, phase: 0.0)

path.lineWidth = 8.0
path.lineCapStyle = .butt
UIColor.magenta.set()
path.stroke()

Here is how to draw Dotted Lines using UIBezierPath:

let  path = UIBezierPath()

let  p0 = CGPointMake(CGRectGetMinX(self.bounds), CGRectGetMidY(self.bounds))
path.moveToPoint(p0)

let  p1 = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMidY(self.bounds))
path.addLineToPoint(p1)

let  dashes: [ CGFloat ] = [ 0.0, 16.0 ]
path.setLineDash(dashes, count: dashes.count, phase: 0.0)
path.lineWidth = 8.0
path.lineCapStyle = .Round
UIColor.magentaColor().set()
path.stroke()

Here is how to draw Dashed Lines Using CGContext:

let  context: CGContext = UIGraphicsGetCurrentContext()!

let  p0 = CGPointMake(CGRectGetMinX(self.bounds), CGRectGetMidY(self.bounds))
CGContextMoveToPoint(context, p0.x, p0.y)

let  p1 = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMidY(self.bounds))
CGContextAddLineToPoint(context, p1.x, p1.y)

let  dashes: [ CGFloat ] = [ 16.0, 32.0 ]
CGContextSetLineDash(context, 0.0, dashes, dashes.count)

CGContextSetLineWidth(context, 8.0)
CGContextSetLineCap(context, .Butt)
UIColor.blueColor().set()
CGContextStrokePath(context)
Beseech answered 16/8, 2016 at 18:57 Comment(1)
Line not coming when I am passing two buttons bound as parameter, How to draw dotted line between two UIbutton. here is my code let path = UIBezierPath() let p0 = CGPointMake(CGRectGetMinX(self.button1.bounds), CGRectGetMidY(self.button1.bounds)) path.moveToPoint(p0) let p1 = CGPointMake(CGRectGetMaxX(self.button2.bounds), CGRectGetMidY(self.button2.bounds)) path.addLineToPoint(p1)Tricolor
R
24

By Using Custom Class inherited from UIView also supports Storyboard.

All you need to do is make a view in storyboard assign class to that view and see the magic in storyboard.

@IBDesignable
class DashedLineView : UIView {
    @IBInspectable var perDashLength: CGFloat = 2.0
    @IBInspectable var spaceBetweenDash: CGFloat = 2.0
    @IBInspectable var dashColor: UIColor = UIColor.lightGray


    override func draw(_ rect: CGRect) {
        super.draw(rect)
        let  path = UIBezierPath()
        if height > width {
            let  p0 = CGPoint(x: self.bounds.midX, y: self.bounds.minY)
            path.move(to: p0)

            let  p1 = CGPoint(x: self.bounds.midX, y: self.bounds.maxY)
            path.addLine(to: p1)
            path.lineWidth = width

        } else {
            let  p0 = CGPoint(x: self.bounds.minX, y: self.bounds.midY)
            path.move(to: p0)

            let  p1 = CGPoint(x: self.bounds.maxX, y: self.bounds.midY)
            path.addLine(to: p1)
            path.lineWidth = height
        }

        let  dashes: [ CGFloat ] = [ perDashLength, spaceBetweenDash ]
        path.setLineDash(dashes, count: dashes.count, phase: 0.0)

        path.lineCapStyle = .butt
        dashColor.set()
        path.stroke()
    }

    private var width : CGFloat {
        return self.bounds.width
    }

    private var height : CGFloat {
        return self.bounds.height
    }
}
Receivership answered 29/1, 2019 at 7:54 Comment(3)
You need assign backgroundColor = .clear to make it work properly on every color of viewFever
@Fever i think IBInspectable bgColor is better option instead of just giving statically clear color.Receivership
Perfect answer! Should get more thumbs up!Dermot
N
17

Here's an easy to use UIView that draws a dashed line.

I took @Fan Jin's answer and made an UIView subclass that should work just fine with Auto Layout.

Swift 5.3, Xcode 12

import UIKit

public class DashedView: UIView {

    public struct Configuration {
        public var color: UIColor
        public var dashLength: CGFloat
        public var dashGap: CGFloat

        public init(
            color: UIColor,
            dashLength: CGFloat,
            dashGap: CGFloat) {
            self.color = color
            self.dashLength = dashLength
            self.dashGap = dashGap
        }

        static let `default`: Self = .init(
            color: .lightGray,
            dashLength: 7,
            dashGap: 3)
    }

    // MARK: - Properties

    /// Override to customize height
    public class var lineHeight: CGFloat { 1.0 }

    override public var intrinsicContentSize: CGSize {
        CGSize(width: UIView.noIntrinsicMetric, height: Self.lineHeight)
    }

    public final var config: Configuration = .default {
        didSet {
            drawDottedLine()
        }
    }

    private var dashedLayer: CAShapeLayer?

    // MARK: - Life Cycle

    override public func layoutSubviews() {
        super.layoutSubviews()

        // We only redraw the dashes if the width has changed.
        guard bounds.width != dashedLayer?.frame.width else { return }

        drawDottedLine()
    }

    // MARK: - Drawing

    private func drawDottedLine() {
        if dashedLayer != nil {
            dashedLayer?.removeFromSuperlayer()
        }

        dashedLayer = drawDottedLine(
            start: bounds.origin,
            end: CGPoint(x: bounds.width, y: bounds.origin.y),
            config: config)
    }

}

// Thanks to: https://mcmap.net/q/381621/-how-to-make-a-dashed-line-in-swift
private extension DashedView {
    func drawDottedLine(
        start: CGPoint,
        end: CGPoint,
        config: Configuration) -> CAShapeLayer {
        let shapeLayer = CAShapeLayer()
        shapeLayer.strokeColor = config.color.cgColor
        shapeLayer.lineWidth = Self.lineHeight
        shapeLayer.lineDashPattern = [config.dashLength as NSNumber, config.dashGap as NSNumber]

        let path = CGMutablePath()
        path.addLines(between: [start, end])
        shapeLayer.path = path
        layer.addSublayer(shapeLayer)

        return shapeLayer
    }
}

Nitroglycerin answered 10/3, 2021 at 15:51 Comment(2)
Thank you so much. This answer is perfect for me. Will you please modify this class so that we can use this to create both vertical and horizontal line. Like, we will pass orientation param on configuration and based on that line will be drawn. and orientation param will be enum. something like this enum Orientation { case HORIZONTAL case VERTICAL } Thanks again.Spiniferous
Only using this way I was able to add a dashed line to my layout. Thank youSandi
S
9

My extension method built from @FanJins answer

extension UIView {

    func createDashedLine(from point1: CGPoint, to point2: CGPoint, color: UIColor, strokeLength: NSNumber, gapLength: NSNumber, width: CGFloat) {
        let shapeLayer = CAShapeLayer()

        shapeLayer.strokeColor = color.cgColor
        shapeLayer.lineWidth = width
        shapeLayer.lineDashPattern = [strokeLength, gapLength]

        let path = CGMutablePath()
        path.addLines(between: [point1, point2])
        shapeLayer.path = path
        layer.addSublayer(shapeLayer)
    }
}

Then calling method looks something like this:

let topPoint = CGPoint(x: view.frame.midX, y: view.bounds.minY)
let bottomPoint = CGPoint(x: view.frame.midX, y: view.bounds.maxY)

view.createDashedLine(from: topPoint, to: bottomPoint, color: .black, strokeLength: 4, gapLength: 6, width: 2)
Stalagmite answered 21/5, 2019 at 8:35 Comment(0)
M
8

Pretty easy UIView Extension for SWIFT 4.2:

extension UIView {
    private static let lineDashPattern: [NSNumber] = [2, 2]
    private static let lineDashWidth: CGFloat = 1.0

    func makeDashedBorderLine() {
        let path = CGMutablePath()
        let shapeLayer = CAShapeLayer()
        shapeLayer.lineWidth = UIView.lineDashWidth
        shapeLayer.strokeColor = UIColor.lightGray.cgColor
        shapeLayer.lineDashPattern = UIView.lineDashPattern
        path.addLines(between: [CGPoint(x: bounds.minX, y: bounds.height/2),
                                CGPoint(x: bounds.maxX, y: bounds.height/2)])
        shapeLayer.path = path
        layer.addSublayer(shapeLayer)
    }
}
Mushy answered 18/4, 2019 at 17:43 Comment(1)
It didn't work for me. I did a call like the following and it didn't work: uiView.makeDashedBorderLine()Rafiq
T
1

Objective C

@user3230875 answer helped me to understand what's needed to draw a dotted line.
so I hope this answer might help an Obj-C seeker

//dashed line
    path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(dashedLineStartX, dashedLineStartY)];
    [path addLineToPoint:CGPointMake(dashedLineEndX, dashedLineEndY)];
    path.lineWidth = 5;
    [color setStroke];
    CGFloat dashes[] = {4.0,8.0};
    [path setLineDash:dashes count:2 phase:0.0];
    path.lineCapStyle = kCGLineCapButt;
    [path stroke];
Tetrafluoroethylene answered 5/9, 2018 at 18:29 Comment(0)
R
0

modified version of @clément-cardonnel 's answer.

Enhanced with isVertical option and IBInspectable properties

class DottedLineView : UIView {
        @IBInspectable var perDashLength: CGFloat = 2.0
        @IBInspectable var spaceBetweenDash: CGFloat = 2.0
        @IBInspectable var dashColor: UIColor = UIColor.gray
        @IBInspectable var lineWidth: CGFloat = 2.0
        @IBInspectable var isVertical: Bool = false
        
    private var dashedLayer: CAShapeLayer?
    
    override public func layoutSubviews() {
        super.layoutSubviews()
        
        guard bounds.width != dashedLayer?.frame.width,
              bounds.height != dashedLayer?.frame.height
        else { return }
        
        drawDottedLine()
    }
    
    private func drawDottedLine() {
        if dashedLayer != nil {
            dashedLayer?.removeFromSuperlayer()
        }
        
        var startPoint = CGPoint(
            x: bounds.width / 2 + lineWidth / 2,
            y: 0
        )
        var endPoint = CGPoint(
            x: bounds.width / 2 + lineWidth / 2,
            y: bounds.height
        )
        
        if !isVertical {
            startPoint = CGPoint(
                x: 0,
                y: bounds.height / 2 + lineWidth / 2
            )
            endPoint = CGPoint(
                x: bounds.width,
                y: bounds.height / 2 + lineWidth / 2
            )
        }
        
        dashedLayer = drawDottedLine(
            startPoint: startPoint,
            endPoint: endPoint
        )
    }
    
    private func drawDottedLine(startPoint: CGPoint, endPoint: CGPoint) -> CAShapeLayer {
        let shapeLayer = CAShapeLayer()
        shapeLayer.strokeColor = dashColor.cgColor
        shapeLayer.lineWidth = self.lineWidth
        shapeLayer.lineDashPattern = [perDashLength as NSNumber, spaceBetweenDash as NSNumber]
        
        let path = CGMutablePath()
        path.addLines(between: [startPoint, endPoint])
        shapeLayer.path = path
        layer.addSublayer(shapeLayer)
        
        return shapeLayer
    }
}
Ropy answered 31/12, 2023 at 0:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.