Search code examples
iosswiftuitapgesturerecognizeruipangesturerecognizer

Panning a UIView only from 1 subview


I have a UIView (alertView) that serves as a custom alert. Inside this UIView, I have several pieces of interaction. I would like just the top portion of this custom alert (alertHeaderView) to be able to be panned to move the alertView, while still maintaining the functionality of the alertView contents.

I currently have this half-working. In storyboard, I added the pan gesture recognizer to the whole alertView. My pan functionality works perfect, but it's preventing all the interaction from happening within the view. This is the problem.

@IBAction func panAlert(_ sender: UIPanGestureRecognizer) {
    // ... All my pan code.
}

I've created an outlet for the header:

@IBOutlet weak var alertHeaderView: UIView!

Is there a way I can pan the entire alertView, ONLY from touches from alertHeaderView?


Solution

  • here is my tried code - it limit the view to be moved from specific location set

    import UIKit
    
    class AlertWithPan: UIViewController
    {
        @IBOutlet weak var alertView: UIView!
    
        override func viewDidLoad()
        {
            super.viewDidLoad()
    
            // Do any additional setup after loading the view.
            self.alertView.isHidden = true
            self.addPanGesture()
        }
    
        func addPanGesture()
        {
            let gesture : UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action:#selector(AlertWithPan.handlePanGesture(panGesture:)))
            self.alertView.addGestureRecognizer(gesture)
        }
    
    
    
        @objc func handlePanGesture(panGesture: UIPanGestureRecognizer)
        {
    
            ///Get my Location
            let touchPosition = panGesture.location(in: self.alertView)
            print("currentTouch: \(touchPosition.y), ViewOrigin_Y: \(String(describing: panGesture.view?.frame.origin.y))")
    
            //Let us limit the frame Movement on specific location 
            //In your case you had initialised a header View supposingly it is having height 32 
            //So we will set TouchPosition not to move Ahead of that View
            //I am using here touch Location in AlertView 
            //Setting it to limit upto `self.alertView.frame.size.height*0.2`
    
    
            //self.alertView.frame.size.height*0.2 - This refers to Height of your Header View 
            //if a view having total height of Hundred then If I write self.alertView.frame.size.height*0.2
            //This means just 20 percent of height - 20 out of hundred 
            //we had added pan in AlertView , I.e So we need to set a proper height in which Pan will be allowed to set translation 
            //self.alertView.frame.size.height*0.2 - using this I made the view to move only in case if touch location is with in the header size I.e 20 
            // if you had provided static height of header 
            //Then Can get this by using like pan gesture.origin.y + header view height 
            // So check will be  touchPosition.y > Total of both
            if touchPosition.y > self.alertView.frame.size.height*0.2 {
                print("High")
            }
            else{
                print("Low")
                ///Get the changes
                let translation = panGesture.translation(in: self.view)
    
                ///Move view to required Position
                panGesture.view!.center = CGPoint(x: panGesture.view!.center.x, y: panGesture.view!.center.y + translation.y)
                panGesture.setTranslation(CGPoint.zero, in: self.view)
            }
    
    
    
        }
    
    
        @IBAction func showMyAlertView(_ sender: Any)
        {
            self.alertView.isHidden = false
        }
    }
    

    my Storyboard:

    enter image description here

    Working Video :

    https://drive.google.com/open?id=1ZZuqxc34BUEZQ7WGFJiA2lU6ydIwqEjn