Search code examples
swiftcashapelayer

How to sort correct CAShapeLayers in UIView and child button?


I create a parent view with CAShapeLayer, and create a child button with CAShapeLayer.

class TestButton: UIButton {
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: CGRect) {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 60, y: 100))
        path.addLine(to: CGPoint(x: 0, y: 100))
        path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 100, startAngle: .pi, endAngle: .pi*1.5, clockwise: true)
        path.addLine(to: CGPoint(x: 100, y: 60))
        path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 40, startAngle: .pi*1.5, endAngle: .pi, clockwise: false)
        path.close()
        
        let drawLayer = CAShapeLayer.init()
        drawLayer.path = self.path.cgPath
        drawLayer.fillColor = UIColor.green.cgColor
        self.layer.addSublayer(drawLayer)
    }
}

class TestView:UIView{
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: CGRect) {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: 0))
        path.addLine(to: CGPoint(x: 0, y: rect.height-20))
        path.addLine(to: CGPoint(x: rect.width/2, y: rect.height))
        path.addLine(to: CGPoint(x: rect.width, y: rect.height-20))
        path.addLine(to: CGPoint(x: rect.width, y: 0))
        path.addLine(to: CGPoint(x: 0, y: 0))
        path.close()
        
        let drawLayer = CAShapeLayer.init()
        drawLayer.path = self.path.cgPath
        drawLayer.fillColor = UIColor.red.cgColor
        self.layer.addSublayer(drawLayer)
    }
}

createView

func createView() {
    let announce = TestAnnotationview.init(frame: CGRect.init(x: 50, y: 400, width: 150, height: 150))
    announce.backgroundColor = .blue
    self.view.addSubview(announce)
    let btn = TestButton2.init(frame: CGRect.init(x: 0, y: 0, width: 150, height: 150))
    btn.backgroundColor = .yellow
    announce.addSubview(btn)
}

It run at simular like this, parent view's CAShapeLayers cover its child button CAShapeLayers.

enter image description here

but it show in Debug View Hierarchy like this.

enter image description here

How do i sort them like Debug View Hierarchy? Thanks for answer!!


Solution

  • Don't create and add a new sublayer in draw(_ rect:). You don't control how often that method is called, and you are adding a new sublayer every time it is.

    Overriding drawRect is generally not a great idea, since it can affect the drawing of other parts of the view and performance during animations.

    Create and add the sublayer once, in your init method, for example, and position it if you need to in layoutSubviews. Don't override draw(_ rect:).