Home > Software engineering >  How do you pass a gesture between subviews in UIKit?
How do you pass a gesture between subviews in UIKit?

Time:06-25

I've got a ViewController with three subviews. I'm trying to get them to detect touches in their bounds from a starting point outside their bounds without the user lifting their finger (ie the user dragging into the view). I thought hitTest would do this but it only works for separate taps. I assume this is probably passing a gesture through instead but I've not found out how to implement this.

class SuperViewController: UIViewController {

    var view01 = UIView(frame: CGRect(x: 0, y: 0, width: 1000,
                                          height: 800))
    var view02 = UIView(frame: CGRect(x: 0, y: 0, width: 600,
                                          height: 400))
    let view03 = UIView(frame: CGRect(x: 0, y: 0, width: 300,
                                      height: 200))
    
  
    
    override func viewDidLoad() {
        
        super.viewDidLoad()

        self.view = TestView()
        
        view01.backgroundColor = .orange
        view02.backgroundColor = .blue
        view03.backgroundColor = .green
        
        self.view.addSubview(view01)
        self.view.addSubview(view02)
        self.view.addSubview(view03)
    }
    
}

Which produces this enter image description here

And then I've subclassed UIView for the SuperViewController's view.

class TestView: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        guard self.isUserInteractionEnabled, !isHidden, alpha > 0.01 else {return nil}
        
        if self.point(inside: point, with: event) {
            for subview in subviews.reversed() {

                let hitView = subview.hitTest(point, with: event)
                if hitView != nil {
                    hitView?.backgroundColor = .red
                    return hitView
                }
            }
            return self
        }
        return nil
    }
}

So each one turns red when the user taps. But ideally I want them to each respond with one drag from the top left corner of the screen to the other.

CodePudding user response:

You can accomplish this with a UIPanGestureRecognizer.

Here's an example below:

class ViewController: UIViewController {
    
    var view01 = UIView(frame: CGRect(x: 0, y: 0, width: 1000,
                                          height: 800))
    var view02 = UIView(frame: CGRect(x: 0, y: 0, width: 600,
                                          height: 400))
    let view03 = UIView(frame: CGRect(x: 0, y: 0, width: 300,
                                      height: 200))
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        view01.backgroundColor = .orange
        view02.backgroundColor = .blue
        view03.backgroundColor = .green
        
        self.view.addSubview(view01)
        self.view.addSubview(view02)
        self.view.addSubview(view03)
        
        let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
        self.view.addGestureRecognizer(gestureRecognizer)
    }

    @objc
    private func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
        guard let view = gestureRecognizer.view else {
            return
        }
        
        let translation = gestureRecognizer.translation(in: view)
        
        for subview in view.subviews.reversed() {
            if let hitView = subview.hitTest(translation, with: nil) {
                hitView.backgroundColor = .red
                return
            }
        }
    }
}

Pan

  • Related