Search code examples
iosuiviewuikitcgcontext

CGContext 'addPath' to the existing drawing


I have a CGPath drawn in a custom UIView as follows. There is a refresh button that is supposed to add new line to the path already drawn.

 private func refresh() {
    self.setNeedsDisplay()
}

override func draw(_ rect: CGRect){
    guard let context = UIGraphicsGetCurrentContext() else {
        return
    }
    
    context.setLineWidth(1)
    context.addPath(self.newPathPart())
    context.setStrokeColor(UIColor.white.cgColor)
    context.interpolationQuality = .none
    context.setAllowsAntialiasing(false)
    context.setShouldAntialias(false)
    context.strokePath()
   
}

private func newPathPart() -> CGPath {
   let lineWidth: CGFloat = 1
    
    let mPath        = CGMutablePath()
    
    if lastPoint == nil {
        lastPoint = CGPoint(x: self.bounds.midX - lineWidth/2, y: self.bounds.midY - lineWidth/2)
    }
    
    mPath.move(to: lastPoint!)
   
    mPath.addLine(to: CGPoint(x: lastPoint!.x + 15, y: lastPoint!.y + 15))

    lastPoint = CGPoint(x: lastPoint!.x + 15, y: lastPoint!.y + 15)
    mPath.closeSubpath()
   
    return mPath
}

I had an impression that the newPartPath() will be appended to existing path that is drawn but that seems not to be the case. I wish to optimise the code so that I do not completely redraw the whole path on every refresh, but just the path that is added. How do I achieve it?


Solution

  • You need to keep on hand a CGMutablePath, or a collection of CGPaths, so that you can keep accumulating new path parts in an actual CGPath.

    When draw is called, it has a rect. You are ignoring that parameter. Don't ignore it. You only need to supply the part of the drawing that is in that rect. So examine the rect and draw in such a way as to supply the missing part of the drawing that does into it. In other words, you draw just the parts of your path that intersect that rect.

    Note that if you are the one responsible for knowing that there is a new part of the path waiting to be drawn, you can call setNeedsDisplay(in:) with the rect of that part of the path, so that that is the rect that is asked for in draw.