默认情况下,如果一个UIButton超出了它的父视图,那么超出父视图的部分,是不响应点击事件的,当需要超出父视图依然相应点击事件的时候,就需要重写UIView的
func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView?
方法。此方法中的point是在接受点击的view(即父视图)坐标体系中的坐标,会递归调用:
public func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool
方法,因此,我们需要得到这个point相对于子视图(以UIButton为例)的坐标点,可以用:
public func convertPoint(point: CGPoint, fromView view: UIView?) -> CGPoint
这个方法获得,
有了这个点,就可以判断这个点是否在子视图的范围内,并相应事件,举例如下:
class TestView:UIView {
var testBtn:UIButton!
override init(frame: CGRect) {
super.init(frame: frame);
testBtn = UIButton(type: UIButtonType.Custom);
testBtn.frame = CGRectMake(-50, -50, 50, 50);
testBtn.backgroundColor = UIColor.blueColor();
testBtn.addTarget(self, action: #selector(testBtnClicked), forControlEvents: UIControlEvents.TouchUpInside);
self.addSubview(testBtn);
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
// 得到不处理的情况下,相应点击的view结果,目的是不影响其它的点击
let result = super.hitTest(point, withEvent: event);
// 得到点相对于button的坐标
let testBtnPoint = self.testBtn.convertPoint(point, fromView: self);
// 如果坐标在button内,返回这个button,就会相应button的事件
if (self.testBtn.pointInside(testBtnPoint, withEvent: event)) {
return self.testBtn;
}
// 返回super的响应点击的view
return result;
}
func testBtnClicked() {
print("btn clicked");
}
}