Bigair Bigair - 1 month ago 13
Swift Question

UIGestureRecognizer not detected on subview

I made a UIView subclass and added a circle view on top right corner of the view. Then I added

UIPanGestureRecognizer
to the circle view.

The problem is that gesture is only recognized on left bottom part of circle where the circle is located over the super view.

How can I make entire circle to property detected gesture?

enter image description here

Following is entire class code of UIView subclass I made.

import UIKit

class ResizableImageView: UIView {


private let circleWidth: CGFloat = 40

var themeColor: UIColor = UIColor.magentaColor()

lazy var cornerCircle: UIView = {
let v = UIView()

v.layer.cornerRadius = self.circleWidth / 2
v.layer.borderWidth = 1
v.layer.borderColor = self.themeColor.CGColor

let panGesture = UIPanGestureRecognizer(target: self, action: #selector(buttonTouchMoved) )
v.addGestureRecognizer(panGesture)

return v
}()





// Init

override init(frame: CGRect) {
super.init(frame: frame)

setupSubviews()
configureSelf()
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}



func setupSubviews() {

// Add cornerButton to self and set auto layout
addSubview( cornerCircle )
addConstraintsWithFormat("H:[v0(\(circleWidth))]", views: cornerCircle) // Extension code for setting auto layout
addConstraintsWithFormat("V:[v0(\(circleWidth))]", views: cornerCircle)
addConstraint(NSLayoutConstraint(item: cornerCircle, attribute: .CenterX, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: cornerCircle, attribute: .CenterY, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0))


}

func configureSelf() {

// Set border
layer.borderWidth = 1
layer.borderColor = themeColor.CGColor
}




// Gesture Event

func buttonTouchMoved(gestureRecognizer: UIPanGestureRecognizer) {

let point = gestureRecognizer.locationInView(self)
print(point)

}


}


ViewController

import UIKit

class ImageViewCheckController: UIViewController {

let imageView: ResizableImageView = {
let iv = ResizableImageView()
return iv
}()


override func viewDidLoad() {
super.viewDidLoad()

title = "ImageViewCheck"

view.backgroundColor = UIColor.whiteColor()

setupSubviews()
}

func setupSubviews() {
view.addSubview( imageView )

view.addConstraintsWithFormat("V:|-100-[v0(200)]", views: imageView)
view.addConstraintsWithFormat("H:|-50-[v0(100)]", views: imageView)

}

}

Answer

Normally, there is no touch on a subview outside the bounds of its superview.

To change this, you will have to override hitTest(point:withEvent:) on the superview to alter the way hit-testing works:

override func hitTest(point: CGPoint, withEvent e: UIEvent?) -> UIView? {
    if let result = super.hitTest(point, withEvent:e) {
        return result
    }
    for sub in self.subviews.reverse() {
        let pt = self.convertPoint(point, toView:sub)
        if let result = sub.hitTest(pt, withEvent:e) {
            return result
        }
    }
    return nil
}