Passing touches from UIView to a child view?

I made an extension with a UIView that takes a SwiftUI view, gets its UIView, and then adds it as a subview. But now the subview isn't receiving any touches and idk how to fix that. I've already tried point(inside:with:) but it doesn't seem to work. I've also tried forwarding the touches from touchesBegan, touchesMoved, etc., but that didn't work either.

Any help or advice would be greatly appreciated!

Extension with the UIView:

// Add view modifier to View
extension View {
    func transformable() -> some View {
        modifier(Transformable())
    }
}

// View modifier
struct Transformable: ViewModifier {
    func body(content: Content) -> some View {
        TransformableUIView(content: content)
    }
}

// Wrap UIView
struct TransformableUIView<V>: UIViewRepresentable where V: View {
    private var content: V
    
    init(content: V) {
        self.content = content
    }
    
    func makeUIView(context: Context) -> TransformableView<V> {
        TransformableView(content: content)
    }

    func updateUIView(_ uiView: TransformableView<V>, context: Context) {}
}

// View that handles zoom, pan, and rotate gestures
class TransformableView<V>: UIView, UIGestureRecognizerDelegate where V: View {
    private var content: V
    private var initialCenter: CGPoint = .zero
    private var totalScale: CGFloat = 1.0
    private var boundsDidSet = false
    
    required init(content: V) {
        self.content = content
        super.init(frame: .zero)

        self.addSubview(content.uiView)
        
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panPiece(_:)))
        panGesture.minimumNumberOfTouches = 2
        panGesture.maximumNumberOfTouches = 2
        panGesture.delegate = self
        self.addGestureRecognizer(panGesture)
        
        let scaleGesture = UIPinchGestureRecognizer(target: self, action: #selector(scalePiece(_:)))
        scaleGesture.delegate = self
        self.addGestureRecognizer(scaleGesture)
        
        let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotatePiece(_:)))
        rotateGesture.delegate = self
        self.addGestureRecognizer(rotateGesture)
    }
    
    // Position content in center of view
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // Return if bounds are already set
        if boundsDidSet {
            return
        }
        guard let piece = self.subviews.first else { return }
        piece.center = CGPoint(x: self.bounds.size.width / 2, y: self.bounds.size.height / 2)
        boundsDidSet = true
    }
    
    // Function called when pan gesture is recognized
    @objc private func panPiece(_ gestureRecognizer: UIPanGestureRecognizer) {
        guard let piece = gestureRecognizer.view?.subviews.first else { return }
        // Get the changes in the X and Y directions relative to
        // the superview's coordinate space.
        let translation = gestureRecognizer.translation(in: piece.superview)
        if gestureRecognizer.state == .began {
            // Save the view's original position.
            self.initialCenter = piece.center
        }
        // Update the position for the .began, .changed, and .ended states
        if gestureRecognizer.state != .cancelled {
            // Add the X and Y translation to the view's original position.
            var newCenter = CGPoint(x: initialCenter.x + translation.x, y: initialCenter.y + translation.y)
            // Prevent content from leaving view
            newCenter.x = clamp(value: newCenter.x, min: 0, max: self.bounds.width)
            newCenter.y = clamp(value: newCenter.y, min: 0, max: self.bounds.height)
            piece.center = newCenter
        }
        else {
            // On cancellation, return the piece to its original location.
            piece.center = initialCenter
        }
    }
    
    // Function called when scale gesture is recognized
    @objc private func scalePiece(_ gestureRecognizer : UIPinchGestureRecognizer) {
        guard let piece = gestureRecognizer.view?.subviews.first else { return }
        if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
            // Set min/max zoom
            let newScale = clamp(value: totalScale * gestureRecognizer.scale, min: 0.2, max: 20) / totalScale
            piece.transform = (piece.transform.scaledBy(x: newScale, y: newScale))
            gestureRecognizer.scale = 1.0
            totalScale *= newScale
       }

    }
    
    // Function called when rotate gesture is recognized
    @objc private func rotatePiece(_ gestureRecognizer : UIRotationGestureRecognizer) {
        guard let piece = gestureRecognizer.view?.subviews.first else { return }
        if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
          piece.transform = piece.transform.rotated(by: gestureRecognizer.rotation)
          gestureRecognizer.rotation = 0
       }
    }
    
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    
    func clamp(value: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat {
        if value < min {
            return min
        } else if value > max {
            return max
        } else {
            return value
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Get UIView from SwiftUI View:

// Get UIView from SwiftUI View
extension View {
    var uiView: UIView {
        UIHostingController(rootView: self).view
    }
}

ContentView:

struct ContentView: View {
    var body: some View {
        CanvasView()
            .frame(width: 880, height: 608)
            .transformable()
            .background(Color.blue)
    }
}
Answered by Frameworks Engineer in 796546022

Adding a SwiftUI view hierarchy to a UIKit hierarchy in the way you're doing is unsupported. You need to add the UIHostingController as a child view controller to your view controller (using the standard addChild, addSubview, didMoveToParent sequence of method calls).

Accepted Answer

Adding a SwiftUI view hierarchy to a UIKit hierarchy in the way you're doing is unsupported. You need to add the UIHostingController as a child view controller to your view controller (using the standard addChild, addSubview, didMoveToParent sequence of method calls).

Passing touches from UIView to a child view?
 
 
Q