I am currently trying to build an application somewhat similar to procreate in SwiftUI (much less sophisticated of course ;) ).
My biggest issue is navigation right now. I want to use a 2-Finger pan gesture to navigate around the canvas. I have done plenty of research and I have not yet found a solution on how to implement this with SwiftUI gestures.
My current solution is using a UIViewRepresentable with an attached gesture listener. Unfortunately, this breaks all Gesture recognisers in subviews (which is a lot of them, and I need them all.
The current implementation is this here:
struct TwoFingerNavigationView: UIViewRepresentable {
var draggedCallback: ((CGPoint) -> Void)
var dragEndedCallback: (() -> Void)
class Coordinator: NSObject {
var draggedCallback: ((CGPoint) -> Void)
var dragEndedCallback: (() -> Void)
init(draggedCallback: @escaping ((CGPoint) -> Void),
dragEndedCallback: @escaping (() -> Void)) {
self.draggedCallback = draggedCallback
self.dragEndedCallback = dragEndedCallback
}
@objc func dragged(gesture: UIPanGestureRecognizer) {
if gesture.state == .ended {
self.dragEndedCallback()
} else {
self.draggedCallback(gesture.translation(in: gesture.view))
}
}
}
func makeUIView(context: UIViewRepresentableContext<TwoFingerNavigationView>) -> TwoFingerNavigationView.UIViewType {
let view = UIView(frame: .zero)
let gesture = UIPanGestureRecognizer(target: context.coordinator,
action: #selector(Coordinator.dragged))
gesture.minimumNumberOfTouches = 2
gesture.maximumNumberOfTouches = 2
view.addGestureRecognizer(gesture)
return view
}
func makeCoordinator() -> TwoFingerNavigationView.Coordinator {
return Coordinator(draggedCallback: self.draggedCallback,
dragEndedCallback: self.dragEndedCallback)
}
func updateUIView(_ uiView: UIView,
context: UIViewRepresentableContext<TwoFingerNavigationView>) {
}
}
The usage is as follows:
ZStack {
OtherView()
.gesture() // This will break with this "hack"
TwoFingerNavigationView(draggedCallback: { translation in
var newLocation = startLocation ?? location
newLocation.x += (translation.x / scale)
newLocation.y += (translation.y / scale)
self.location = newLocation
}, dragEndedCallback: {
startLocation = location
})
}
Does anyone have an idea how I could either replicate the functionality with SwiftUI gesture recognisers, or make it work with the UIKit implementation without breaking the gestures in all the children?
Any help and pointers are highly appreciated!