0

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 :

Pin normal image without zooming

Pin big image with zooming

karthikeyan
  • 3,821
  • 3
  • 22
  • 45

0 Answers0