Created
January 10, 2024 11:14
-
-
Save osmanmesutozcan/94de686dc80122aa4e23d0cf6b1ea0a7 to your computer and use it in GitHub Desktop.
Use UIKit gestures on SwiftUI Views
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct ZoomableView<Content: View>: UIViewControllerRepresentable { | |
let gestures: [ZoomableViewGestureType] | |
@ViewBuilder let content: () -> Content | |
func makeUIViewController(context: Context) -> ZoomableViewController<Content> { | |
let vc = ZoomableViewController<Content>() | |
vc.gestures = gestures | |
vc.child = UIHostingController(rootView: content()) | |
return vc | |
} | |
func updateUIViewController(_ vc: ZoomableViewController<Content>, context: Context) { | |
vc.child.rootView = content() | |
} | |
} | |
class ZoomableViewController<Content: View>: UIViewController, UIGestureRecognizerDelegate { | |
var gestures = [ZoomableViewGestureType]() | |
var child: UIHostingController<Content>! | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// Attach to self | |
addChild(child) | |
view.addSubview(child.view) | |
// Prepare child view | |
child.view.backgroundColor = .clear | |
child.view.isMultipleTouchEnabled = true | |
child.view.isUserInteractionEnabled = true | |
child.view.translatesAutoresizingMaskIntoConstraints = false | |
NSLayoutConstraint.activate([ | |
child.view.centerXAnchor.constraint(equalTo: view.centerXAnchor), | |
child.view.centerYAnchor.constraint(equalTo: view.centerYAnchor) | |
]) | |
if gestures.contains(.pan) { | |
//add pan gesture | |
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan)) | |
gestureRecognizer.delegate = self | |
child.view.addGestureRecognizer(gestureRecognizer) | |
} | |
if gestures.contains(.zoom) { | |
//add pinch gesture | |
let pinchGesture = UIPinchGestureRecognizer(target: self, action:#selector(pinchRecognized(pinch:))) | |
pinchGesture.delegate = self | |
child.view.addGestureRecognizer(pinchGesture) | |
} | |
if gestures.contains(.rotate) { | |
//add rotate gesture. | |
let rotate = UIRotationGestureRecognizer.init(target: self, action: #selector(handleRotate(recognizer:))) | |
rotate.delegate = self | |
child.view.addGestureRecognizer(rotate) | |
} | |
} | |
@objc | |
func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) { | |
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed { | |
let translation = gestureRecognizer.translation(in: self.view) | |
// note: 'view' is optional and need to be unwrapped | |
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y) | |
gestureRecognizer.setTranslation(CGPoint.zero, in: self.view) | |
} | |
} | |
@objc | |
func pinchRecognized(pinch: UIPinchGestureRecognizer) { | |
if let view = pinch.view { | |
view.transform = view.transform.scaledBy(x: pinch.scale, y: pinch.scale) | |
pinch.scale = 1 | |
} | |
} | |
@objc | |
func handleRotate(recognizer : UIRotationGestureRecognizer) { | |
if let view = recognizer.view { | |
view.transform = view.transform.rotated(by: recognizer.rotation) | |
recognizer.rotation = 0 | |
} | |
} | |
//MARK:- UIGestureRecognizerDelegate Methods | |
func gestureRecognizer(_: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool { | |
return true | |
} | |
} | |
enum ZoomableViewGestureType { | |
case pan | |
case zoom | |
case rotate | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks!