练习要求:
在下图中点击到绿色Button区域,Button响应(包括YellowView覆盖的绿色Button部分也是由绿色Button来响应)。点击YellowView部分(除覆盖绿色Button外的),YellowView响应。
解决思路:
如果我们只是一味的和之前一样重写绿色Button的hitTest方法,是不能很好的区分YellowView与绿色Button的重合部分的,他会让点击的所有地方都是由绿色Button来响应。显然和我们的想法有了偏离。
那么我们应该在hitTest方法(YellowView中的hitTest方法)的重写中判断一下,如果点恰好也在绿色Button上,那么我们就可以让YellowView不响应这个事件,那么编译器就会接着往下遍历绿色Button,然后让绿色Button去响应。当然这里重写的hitTest方法是重写YellowView中的,多体会几次就可以理解了。
代码:
#import "YellowView.h"
@implementation YellowView
// 输出响应者
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"%s",__func__);
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
// 将point转化成为Button坐标系上的点
CGPoint buttonPoint = [self convertPoint:point toView:_button];
// 如果点在绿色Button上,那么返回nil,也就是YellowView退出遍历了,不让YellowView作为响应者
if ([_button pointInside:buttonPoint withEvent:event]) {
return nil;
}
// 当然如果点不在绿色Button上,那么就接着原来的hitTest方法执行,执行super语句。
return [super hitTest:point withEvent:event];
}
@end
当然除了重写hitTest方法可以实现这个功能,我们也可以重写pointInside方法。
代码:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// 这里的调用者是self,因为point是当前view中的点
CGPoint buttonPoint = [self convertPoint:point toView:_button];
// 需要注意这里的调用者是_button,因为这里的point是buttonPoint也就是绿色Button中的点
if ([_button pointInside:buttonPoint withEvent:event]) {
return nil;
}
return [super pointInside:point withEvent:event];
}
只需要将上面重写hitTest方法的地方替换下来就好了。原理都是一样的。