我们在做项目时总会遇见这样的问题,由于按钮长宽设计的很小导致不容易点击,这时我们就需要在不改变按钮原来尺寸的前提下扩大点击区域。
在解决这个问题前我们需要清楚OC中的事件传递流程是怎样的?
当我们点击屏幕时,首先时UIApplication响应,然后将事件传递到UIWindow,这时就需要找到合适的UIView,当传递到每个控件时会调用:hitTest:withEvent: 方法,在该方法内部,首先判断self.userInteractionEnabled==No或者self.hidden==YES或者self.alpha<0.01,则返回nil,然后通过pointInside:withEvent:来判断点击位置是否在该控件上,不在的话就返回nil,然后通过倒序遍历子视图来找到最终的子控件,也会重复上面两个方法。
通过这个流程,我们知道需要重写响应控件的hitTest:withEvent:来扩大点击区域。
通过新建UIButton分类来实现,在.h文件中写接口:
//扩大点击范围 (利用runtime动态绑定属性,来扩大响应区域)
- (void)setButtonEdgeWIthTop:(CGFloat)topleft:(CGFloat)leftbottom:(CGFloat)bottomright:(CGFloat)right;
由于分类中无法定义实例变量,我们需要用到关联对象的方法来,具体如下:
先引入头文件#import<objc/runtime.h>
定义静态变量:
static char *const xi_topKey;
static char *const xi_leftKey;
static char *const xi_bottomKey;
static char *const xi_rightKey;
实现接口:
- (void)setButtonEdgeWIthTop:(CGFloat)topleft:(CGFloat)leftbottom:(CGFloat)bottomright:(CGFloat)right {
objc_setAssociatedObject(self, xi_topKey, @(top), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(self, xi_leftKey, @(left), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(self, xi_bottomKey, @(bottom), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(self, xi_rightKey, @(right), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIView*)hitTest:(CGPoint)pointwithEvent:(UIEvent*)event {
CGRectrect = [selfenLargedRect];
if (CGRectEqualToRect(rect, self.bounds)) {
return [superhitTest:pointwithEvent:event];
}else{
returnCGRectContainsPoint(rect, point) ?self:nil;
}
}
- (CGRect)enLargedRect {
NSNumber *topEdge = objc_getAssociatedObject(self, xi_topKey);
NSNumber *leftEdge = objc_getAssociatedObject(self, xi_leftKey);
NSNumber*bottomEdge =objc_getAssociatedObject(self,xi_bottomKey);
NSNumber *rightEdge = objc_getAssociatedObject(self, xi_rightKey);
if(topEdge && leftEdge && bottomEdge && rightEdge) {
return CGRectMake(self.bounds.origin.x - [leftEdge floatValue],
self.bounds.origin.y- [topEdgefloatValue],
self.bounds.size.width+ [leftEdgefloatValue] + [rightEdgefloatValue],
self.bounds.size.height+ [topEdgefloatValue] + [bottomEdgefloatValue]);
}else{
returnself.bounds;
}
}
这样在按钮初始化时通过调用分类文件的接口就可以扩大你想要扩大的区域。