Search code examples
iosswiftswiftuicgcontext

Wrapping UIView around the SwiftUI, that the touch and drawn coordinate is now mis-aligned?


I have a Canvas view as below

class Canvas: UIView {
    
    override func draw(_ rect: CGRect){
        super.draw(rect)
        
        guard let context = UIGraphicsGetCurrentContext() else { return }
        
        paths.forEach { path in
            switch(path.type) {
            case .move:
                context.move(to: path.point)
                break
            case .line:
                context.addLine(to: path.point)
                break
            }
        }
        
        context.setLineWidth(10)
        context.setLineCap(.round)
        context.strokePath()
    }
    
    var paths = [Path]()
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let point = touches.first?.location(in: nil) else { return }
        paths.append(Path(type: .move, point: point))
        setNeedsDisplay()
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let point = touches.first?.location(in: nil) else { return }
        paths.append(Path(type: .line, point: point))
        setNeedsDisplay()
    }
}

class Path {
    let type: PathType
    let point: CGPoint
    
    init(type: PathType, point: CGPoint) {
        self.type = type
        self.point = point
    }
    
    enum PathType {
        case move
        case line
    }
}

When I load it using a normal ViewController,

class ViewController: UIViewController {
    
    let canvas = Canvas()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(canvas)
        canvas.backgroundColor = .white
        canvas.frame = view.frame
    }
}

All works fine. I can draw as per where the touch happens, as shown below.

enter image description here

However, if I wrap it around SwiftUI framework, as below

struct ContentView: View {
    var body: some View {
        CanvasSwiftUI()
    }
}

struct CanvasSwiftUI : UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        Canvas()
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        uiView.backgroundColor = .white
    }
}

My touch and drawing doesn't match up. The drawing coordinate is lower than where the touch happens, as shown below

enter image description here

Did I miss out anything when wrapping it around the SwiftUI, that the touch and drawn coordinate is now mis-aligned?


Solution

  • The problem you have is not related to SwiftUI, it's in your code

    guard let point = touches.first?.location(in: nil) else { return }
    

    you should use

    guard let point = touches.first?.location(in: self) else { return }