项目中很多时候需要扩大点击(交互)区域,或者子试图超出了父视图后,无法点击或者交互等,我们可以通过响应者链
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
来解决,下面是我封装的一个小控件,分享给大家
show.jpg
1、在category里增加属性
-(void)setEnlargedMargin:(CGFloat)enlargedMargin{ [self setEnlargeEdge:UIEdgeInsetsMake(enlargedMargin, enlargedMargin, enlargedMargin, enlargedMargin)];}-(void)setEnlargeEdge:(UIEdgeInsets)enlargeEdge{ //拓展后的rect CGRect rect=CGRectMake(self.bounds.origin.x-enlargeEdge.left, self.bounds.origin.y-enlargeEdge.top, self.frame.size.width+enlargeEdge.left+enlargeEdge.right, self.frame.size.height+enlargeEdge.top+enlargeEdge.bottom); //存入 objc_setAssociatedObject(self, &key_yjn_enlarged, @[NSStringFromCGRect(rect)], OBJC_ASSOCIATION_RETAIN_NONATOMIC); //挣脱父试图约束 CGRect windowConvertRect = [self convertRect:self.bounds toView:[[[UIApplication sharedApplication] delegate] window]]; [self freeView:self.superview rect:windowConvertRect enlargeEdge:enlargeEdge];}-(NSArray *)enlargedRect{ NSArray *enlargedArr = objc_getAssociatedObject(self, &key_yjn_enlarged); if (enlargedArr) { return enlargedArr; }else{ return @[NSStringFromCGRect(self.bounds)]; }}2、挣脱父试图约束
#pragma mark - 挣脱父试图约束-(void)freeView:(UIView *)superview rect:(CGRect)rect enlargeEdge:(UIEdgeInsets)enlargeEdge{ if(superview == nil) return; //坐标转换 UIWindow * window=[[[UIApplication sharedApplication] delegate] window]; CGRect selfRect = [self convertRect:self.bounds toView:window]; CGRect superViewRect = [superview convertRect:superview.bounds toView:window]; if (CGRectContainsRect(superViewRect,selfRect)) {//完全包含 return; }else{//不完全包含 NSMutableArray *rectArr = [NSMutableArray arrayWithArray:[superview enlargedRect]]; CGRect newRect = CGRectMake(rect.origin.x - superViewRect.origin.x, rect.origin.y - superViewRect.origin.y, rect.size.width, rect.size.height); CGRect newEnlargeRect = CGRectMake(newRect.origin.x-enlargeEdge.left, newRect.origin.y-enlargeEdge.top, newRect.size.width+enlargeEdge.left+enlargeEdge.right, newRect.size.height+enlargeEdge.top+enlargeEdge.bottom); [rectArr addObject:NSStringFromCGRect(newEnlargeRect)]; objc_setAssociatedObject(superview, &key_yjn_enlarged, rectArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [self freeView:superview.superview rect:rect enlargeEdge:enlargeEdge]; }}3、响应者链传递
#pragma mark - 响应者链-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ for (NSString *edgeStr in [self enlargedRect]) { CGRect rect= CGRectFromString(edgeStr); if (CGRectContainsPoint(rect,point)) { return YES; } } return NO;}-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ // 1.判断下窗口是否接收事件 if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01){ return nil; } // 2.判断下点在不在窗口上 // 不在窗口上 if ([self pointInside:point withEvent:event] == NO){ return nil; } // 3.从后往前遍历子控件数组 int count = (int)self.subviews.count; for (int i = count - 1; i >= 0; i--) { // 获取子控件 UIView *childView = self.subviews[i]; // 坐标系的转换,把窗口上的点转换为子控件上的点 // 把自己控件上的点转换成子控件上的点 CGPoint childP = [self convertPoint:point toView:childView]; UIView *fitView = [childView hitTest:childP withEvent:event]; if (fitView) { // 假如能找到最合适的view return fitView; } } // 4.没有找到更合适的view,也就是没有比自己更合适的view return self;}4、【注】假如要挣脱约束,请想把view加到父view上,如[self.view addSubview:view];后才能增加enlargeEdge属性,否则不生效。demo地址 yinjining/hitEnlarged