I am creating a sketch or canvas editor using the Apple Pencil Kit and I want to add moveable, rotatable, and zoomable items (text, image, etc.) to canvas. When I use the Text element in SwiftUI and add Drag Gesture, Magnification Gesture, and Rotate Gesture, the drag gesture doesn't work simultaneously with the other gestures. So, I have decided to use UIViewRepresentable and create elements on the UIKit side. However, now I am unable to pan any items on the UIKit side. Please could you help me?
//
// SwiftUIView.swift
// Drawing
//
// Created by Furkan Ergün on 24.01.2023.
//
import SwiftUI
struct PanLabel: UIViewRepresentable {
@State private var position = CGSize.zero
@State private var pointSize: CGFloat = 0
func makeUIView(context: Context) -> UILabel {
let label = UILabel()
label.text = "Pan me!"
label.font = UIFont.systemFont(ofSize: 30.0)
label.backgroundColor = UIColor.green
let panGesture = UIPanGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.panLabel(recognizer:)))
label.isUserInteractionEnabled = true
panGesture.delegate = context.coordinator
label.addGestureRecognizer(panGesture)
let pinchGesture = UIPinchGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.pinchLabel(gesture:)))
label.addGestureRecognizer(pinchGesture)
pinchGesture.delegate = context.coordinator
let rotateGesture = UIRotationGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.rotateLabel(gesture:)))
label.addGestureRecognizer(rotateGesture)
rotateGesture.delegate = context.coordinator
return label
}
func updateUIView(_ uiView: UILabel, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIGestureRecognizerDelegate {
var parent: PanLabel
init(_ parent: PanLabel) {
self.parent = parent
}
open var isGestureEnabled = true
// MARK: - gesture handle
// location will jump when finger number change
private var initPanFingerNumber:Int = 1
private var isPanFingerNumberChangedInThisSession = false
private var lastPanPoint:CGPoint = CGPoint(x: 0, y: 0)
@objc func panLabel(recognizer: UIPanGestureRecognizer) {
guard isGestureEnabled, let view = recognizer.view else { return }
// init
if recognizer.state == .began {
lastPanPoint = recognizer.location(in: view)
initPanFingerNumber = recognizer.numberOfTouches
isPanFingerNumberChangedInThisSession = false
}
// judge valid
if recognizer.numberOfTouches != initPanFingerNumber {
isPanFingerNumberChangedInThisSession = true
}
if isPanFingerNumberChangedInThisSession {
return
}
// perform change
let point = recognizer.location(in: view)
view.transform = view.transform.translatedBy(x: point.x - lastPanPoint.x, y: point.y - lastPanPoint.y)
lastPanPoint = recognizer.location(in: view)
}
@objc func pinchLabel(gesture: UIPinchGestureRecognizer) {
// let label = gesture.view as! UILabel
//
// if gesture.state == .began {
// let font = label.font
// parent.pointSize = font!.pointSize
// gesture.scale = label.font!.pointSize * 0.1
// }
//
// if 1 <= gesture.scale && gesture.scale <= 10 {
// label.font = UIFont.systemFont(ofSize: gesture.scale * 10)
//
// resizeLabelToText(textLabel: label)
// }
// gesture.scale = 1
}
@objc func rotateLabel(gesture: UIRotationGestureRecognizer) {
let label = gesture.view as! UILabel
switch gesture.state {
case .changed:
// Update label's transform
label.transform = label.transform.rotated(by: gesture.rotation)
gesture.rotation = 0
default:
break
}
}
func resizeLabelToText(textLabel : UILabel) {
let labelSize = textLabel.intrinsicContentSize
textLabel.bounds.size = labelSize
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
}
struct SwiftUIView: View {
@State private var rotation: Double = 0
@State private var offset: CGSize = .zero
@State private var scale: CGFloat = 1
var body: some View {
VStack{
PanLabel().frame(width: 50, height: 50)
Spacer()
}
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
}
}
And also I tried this solution solution but I can't fit this for SwiftUI side.