I have tried many of solution in online that does not help so i decided to ask help from you all.
I have UIImageView with added Pinchgesture to it. I have requirement to add Pin(UIButton) on UIImageView. Without zooming a imageview i am adding a button by UILongPressGestureRecognizer size of width and Hieght (30*30) given. Its working fine but the issue occurred after zooming a imageview button not taking given size.
Pinview is going to add it as subview of UIImageview.
Tried code :
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var airCraftImageView: UIImageView!
private var magnifyView: MagnifyView?
var draggedButton = DraggableButton()
var lastDraggingPoint : CGPoint?
var currentScale = 0.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
addLongPressGesture()
addPinchZoom()
}
func addPinchZoom() {
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch))
airCraftImageView.isUserInteractionEnabled = true
airCraftImageView.addGestureRecognizer(pinchGesture)
}
fileprivate func addLongPressGesture(){
let lpgr = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
lpgr.minimumPressDuration = 0.5
lpgr.delaysTouchesBegan = true
self.airCraftImageView.isUserInteractionEnabled = true
self.airCraftImageView.addGestureRecognizer(lpgr)
}
//MARK: - UIPinchGestureRecognizer Action -
@objc func handlePinch(gestureReconizer: UIPinchGestureRecognizer) {
if gestureReconizer.state == .began || gestureReconizer.state == .changed{
let scaleResult = gestureReconizer.view?.transform.scaledBy(x: gestureReconizer.scale, y: gestureReconizer.scale)
guard let scale = scaleResult, scale.a > 1, scale.d > 1 else { return }
gestureReconizer.view?.transform = scale
currentScale = Double(gestureReconizer.scale)
gestureReconizer.view?.subviews.forEach({
if $0.isKind(of: DraggableButton.self){
$0.transform = (gestureReconizer.view?.transform.inverted())!
}
})
for pinView in gestureReconizer.view?.subviews ?? []{
if pinView .isKind(of: DraggableButton.self){
}
}
// draggedButton.isHidden = true
gestureReconizer.scale = 1
}else if gestureReconizer.state == .ended{
gestureReconizer.view?.subviews.forEach({
if $0.isKind(of: DraggableButton.self){
$0.transform = (gestureReconizer.view?.transform.inverted())!
}
})
// draggedButton.isHidden = false
}
}
//MARK: - UILongPressGestureRecognizer Action -
@objc func handleLongPress(gestureReconizer: UILongPressGestureRecognizer) {
switch gestureReconizer.state {
case .began:
break
case .cancelled:
break
case .ended:
let point = gestureReconizer.location(in: self.airCraftImageView)
lastDraggingPoint = point
if lastDraggingPoint != nil{
createPin()
}
break
default:
break
}
}
//MARK: - UITapGestureRecognizer Action -
@objc func handleTapGesture(gestureReconizer: UITapGestureRecognizer){
print("Pin Tapped")
guard let popupVC = mainStoaryBoard.instantiateViewController(withIdentifier: "InfoVC") as? InfoVC else { return }
popupVC.delegate = self
popupVC.showPopup(in: self)
}
fileprivate func createPin(){
// let rootWindow = UIApplication.shared.keyWindow
for pinView in self.view.subviews{
if pinView .isKind(of: DraggableButton.self){
pinView.removeFromSuperview()
}
}
draggedButton.frame = CGRect(x: lastDraggingPoint!.x - 30 / 2, y: lastDraggingPoint!.y - 30 / 2 , width: 30, height: 30)
let tapGes = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
tapGes.numberOfTapsRequired = 1
tapGes.delaysTouchesBegan = true
draggedButton.addGestureRecognizer(tapGes)
self.airCraftImageView.addSubview(draggedButton)
}
}
extension ViewController : InfoViewDelegate{
func messageEntered(kInfo: String) {
print("Damaged Info : ", kInfo)
}
}
class DraggableButton: UIButton {
var localTouchPosition : CGPoint?
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override var transform: CGAffineTransform {
get {return super.transform}
set {
super.transform = newValue
for v in subviews {
v.transform = self.transform.inverted()
}
}
}
public func commonInit(){
self.setImage(UIImage(named: "pin2"), for: .normal)
// self.setImage(UIImage(systemName: "mappin"), for: .normal)
self.tintColor = .systemRed
self.backgroundColor = .clear
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
super.touchesBegan(touches, with: event)
let touch = touches.first
self.localTouchPosition = touch?.preciseLocation(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?){
super.touchesMoved(touches, with: event)
let touch = touches.first
guard let location = touch?.location(in: self.superview), let localTouchPosition = self.localTouchPosition else{
return
}
self.frame.origin = CGPoint(x: location.x - localTouchPosition.x, y: location.y - localTouchPosition.y)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?){
super.touchesEnded(touches, with: event)
self.localTouchPosition = nil
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
self.localTouchPosition = nil
}
}
class KSwipePopup: UIViewController {
//MARK: Var
///duration to show/hide popup
var duration = 0.3
///range allow to move popup up and down
var rangeAllowToMove: CGFloat = 50
///save value of popup's origin center y
var originCenterY: CGFloat = 0
var currentNavigation : UINavigationController?
//MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupPopupView()
}
//MARK: Public function
///Override this function to return child viewcontroller's popup view
func getPopupView() -> UIView {
return UIView()
}
///Show popup in a viewcontroller
func showPopup(in viewController: UIViewController, completion: (() -> Void)? = nil) {
let vc = viewController as! ViewController
print(vc)
self.modalPresentationStyle = .overFullScreen
self.loadViewIfNeeded()
let popup = self.getPopupView()
popup.isHidden = true
self.view.addBackgroundTransperant()
viewController.present(self, animated: false, completion: { [weak self] in
guard let self = self else { return }
popup.isHidden = false
var originFrame = popup.frame
popup.frame = CGRect(x: popup.frame.origin.x,
y: self.view.frame.height ,
width: popup.frame.size.width,
height: popup.frame.size.height)
UIView.animate(withDuration: self.duration, animations: {
var tempY = originFrame.maxY
tempY = vc.draggedButton.frame.maxY
originFrame.origin.y = tempY + 20
popup.frame = originFrame
}, completion: { _ in
self.originCenterY = self.getPopupView().center.y
if let completion = completion {
completion()
}
})
})
}
///Dismiss popup with a swipe down animation
func swipeDown(completion: (() -> Void)? = nil) {
UIView.animate(withDuration: duration, animations: { [weak self] in
guard let self = self else { return }
let popup = self.getPopupView()
popup.frame = CGRect(x: popup.frame.origin.x,
y: self.view.frame.height,
width: popup.frame.size.width,
height: popup.frame.size.height)
}, completion: { [weak self] _ in
self?.dismiss(animated: false, completion: completion)
})
}
//MARK: Private function
///Add panGesture to popup view
private func setupPopupView() {
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(gestureRecognizer:)))
getPopupView().addGestureRecognizer(panGesture)
}
///handle panGesture to hide popup when swipe down or move popup to original position
@objc private func handlePan(gestureRecognizer: UIPanGestureRecognizer) {
guard let gestureView = gestureRecognizer.view else { return }
//begin interact
if gestureRecognizer.state == .changed || gestureRecognizer.state == .began {
let translation = gestureRecognizer.translation(in: self.view)
//if move up outside allow range, move to original position
if gestureView.center.y < originCenterY - rangeAllowToMove {
moveToCenterY(gestureView, to: originCenterY)
} else {
//else move the popup with the gesture
gestureView.center = CGPoint(x: gestureView.center.x,
y: gestureView.center.y + translation.y)
}
//reset pan's velocity
gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
}
//end interact
if gestureRecognizer.state == .ended {
//if move down outside allow range, hide
if gestureView.center.y > originCenterY + rangeAllowToMove {
self.swipeDown()
} else {
//else move to original position
moveToCenterY(gestureView, to: originCenterY)
}
}
}
///set a new centerY to a view
private func moveToCenterY(_ view: UIView, to centerY: CGFloat) {
UIView.animate(withDuration: duration) {
view.center = CGPoint(x: view.center.x, y: centerY)
}
}
}
extension UIView{
public func addBackgroundTransperant(){
let transparentView = UIView()
transparentView.backgroundColor = UIColor.black.withAlphaComponent(0.9)
transparentView.frame = self.frame
transparentView.alpha = 0
self.addSubview(transparentView)
self.sendSubviewToBack(transparentView)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: {
transparentView.alpha = 0.5
}, completion: nil)
}
}
internal extension UIApplication {
var keyWindow: UIWindow? {
return UIApplication.shared.windows.filter { $0.isKeyWindow }.first
}
}
Output images :