Search code examples
iosswiftstoryboardcore-graphicsibdesignable

Seeing the draw using IBDesignable+UIView(storyboard) but can't see on app


I'm trying to draw some dashed lines on an app but it only draws on main.storyboard with IBDesignable. When I run the app on iOS simulator, nothing shows. What's happening?

enter image description here

The code to draw:

    @IBDesignable
    class AnalogView: UIView {



        fileprivate let thickHorizontalLayer = CAShapeLayer()
        fileprivate let thinHorizontalLayer = CAShapeLayer()

        @IBInspectable var thickYCoord = 50.0
        @IBInspectable var thinYCoord = 52.5

        override init(frame: CGRect) {
            super.init(frame: frame)

            let thickDashesPath = UIBezierPath()
            thickDashesPath.move(to: CGPoint(x: 0, y: thickYCoord)) //left

            thickDashesPath.addLine(to: CGPoint(x: 340, y: thickYCoord)) //right

            //thickHorizontalLayer.frame           = frame
            thickHorizontalLayer.path            = thickDashesPath.cgPath
            thickHorizontalLayer.strokeColor     = UIColor.black.cgColor //dashes color
            thickHorizontalLayer.lineWidth       = 20
            thickHorizontalLayer.lineDashPattern = [ 1, 83.5 ]
            //thickHorizontalLayer.lineDashPhase   = 0.25

            self.layer.addSublayer(thickHorizontalLayer)

            let thinDashesPath = UIBezierPath()
            thinDashesPath.move(to: CGPoint(x: 0, y: thinYCoord)) //esquerda
            thinDashesPath.addLine(to: CGPoint(x: 340, y: thinYCoord)) //direita

            //thinHorizontalLayer.frame            = frame
            thinHorizontalLayer.path             = thinDashesPath.cgPath
            thinHorizontalLayer.strokeColor      = UIColor.black.cgColor
            thinHorizontalLayer.lineWidth        = 15.0
            thinHorizontalLayer.fillColor        = UIColor.clear.cgColor
            thinHorizontalLayer.lineDashPattern  = [ 0.5, 7.95]
            //thinHorizontalLayer.lineDashPhase    = 0.25

            self.layer.addSublayer(thinHorizontalLayer)

Solution

  • You need to put the common code in a routine that is called by both init(frame:) and init(coder:):

    @IBDesignable
    class AnalogView: UIView {
    
        fileprivate let thickHorizontalLayer = CAShapeLayer()
        fileprivate let thinHorizontalLayer = CAShapeLayer()
    
        @IBInspectable var thickYCoord: CGFloat = 50.0
        @IBInspectable var thinYCoord: CGFloat = 52.5
    
        override init(frame: CGRect = .zero) {
            super.init(frame: frame)
    
            configure()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
    
            configure()
        }
    
        private func configure() {
            let thickDashesPath = UIBezierPath()
            thickDashesPath.move(to: CGPoint(x: 0, y: thickYCoord)) //left
            thickDashesPath.addLine(to: CGPoint(x: 340, y: thickYCoord)) //right
    
            thickHorizontalLayer.path            = thickDashesPath.cgPath
            thickHorizontalLayer.strokeColor     = UIColor.black.cgColor //dashes color
            thickHorizontalLayer.lineWidth       = 20
            thickHorizontalLayer.lineDashPattern = [ 1, 83.5 ]
    
            self.layer.addSublayer(thickHorizontalLayer)
    
            let thinDashesPath = UIBezierPath()
            thinDashesPath.move(to: CGPoint(x: 0, y: thinYCoord)) //esquerda
            thinDashesPath.addLine(to: CGPoint(x: 340, y: thinYCoord)) //direita
    
            thinHorizontalLayer.path             = thinDashesPath.cgPath
            thinHorizontalLayer.strokeColor      = UIColor.black.cgColor
            thinHorizontalLayer.lineWidth        = 15.0
            thinHorizontalLayer.fillColor        = UIColor.clear.cgColor
            thinHorizontalLayer.lineDashPattern  = [ 0.5, 7.95]
    
            self.layer.addSublayer(thinHorizontalLayer)
        }
    }
    

    I'd also suggest declaring an explicit type for your @IBInspectable types, or else you won't be able to adjust them in IB.


    Personally, rather than hard coding the path width, I'd update it when the layout changes. Also, if you're going to make those properties @IBDesignable, you really want to update the paths if they change.

    @IBDesignable
    class AnalogView: UIView {
    
        fileprivate let thickHorizontalLayer = CAShapeLayer()
        fileprivate let thinHorizontalLayer = CAShapeLayer()
    
        @IBInspectable var thickYCoord: CGFloat = 50.0 { didSet { updatePaths() } }
        @IBInspectable var thinYCoord:  CGFloat = 52.5 { didSet { updatePaths() } }
    
        override init(frame: CGRect = .zero) {
            super.init(frame: frame)
    
            configure()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
    
            configure()
        }
    
        private func configure() {
            layer.addSublayer(thickHorizontalLayer)
            layer.addSublayer(thinHorizontalLayer)
        }
    
        override func layoutSubviews() {
            super.layoutSubviews()
            updatePaths()
        }
    
        private func updatePaths() {
            let thickDashesPath = UIBezierPath()
            thickDashesPath.move(to: CGPoint(x: bounds.origin.x, y: thickYCoord)) //left
            thickDashesPath.addLine(to: CGPoint(x: bounds.origin.x + bounds.size.width, y: thickYCoord)) //right
    
            thickHorizontalLayer.path            = thickDashesPath.cgPath
            thickHorizontalLayer.strokeColor     = UIColor.black.cgColor //dashes color
            thickHorizontalLayer.lineWidth       = 20
            thickHorizontalLayer.lineDashPattern = [1.0, NSNumber(value: Double(bounds.size.width - 1) / 4 - 1.0) ]
    
            let thinDashesPath = UIBezierPath()
            thinDashesPath.move(to: CGPoint(x: bounds.origin.x, y: thinYCoord)) //esquerda
            thinDashesPath.addLine(to: CGPoint(x: bounds.origin.x + bounds.size.width, y: thinYCoord)) //direita
    
            thinHorizontalLayer.path             = thinDashesPath.cgPath
            thinHorizontalLayer.strokeColor      = UIColor.black.cgColor
            thinHorizontalLayer.lineWidth        = 15.0
            thinHorizontalLayer.fillColor        = UIColor.clear.cgColor
            thinHorizontalLayer.lineDashPattern  = [0.5, NSNumber(value: Double(bounds.size.width - 1) / 40 - 0.5)]
        }
    }
    

    You might want to adjust the dashing to span the width, too (I'm not sure if you wanted a consistent scale or for it to span the width). But hopefully this illustrates the idea.