美文网首页
利用runtime 扩大UIView的事件响应区域

利用runtime 扩大UIView的事件响应区域

作者: YannChee | 来源:发表于2018-03-08 11:02 被阅读26次

网上也看了一些文章,大部分都是扩大UIButton的点击区域,做法是

  • 自定义一个子类继承自UIButton,重写 pointInside 方法
  • 给UIButton添加一个分类,分类覆盖原有类的 pointInside 方法

但是实际上,除了UIButton外,UIImageView,UILable,甚至UIIView都可能有增加触摸区域的需求,难道都要一个一个去继承吗? 可以自定义一个UIView的子类去实现,然后这些控件再继承这个子类,但是这种做法耦合性太强了,我更喜欢面向切面的方式

//  QYExchangeRecordController.h
#import <UIKit/UIKit.h>

@interface UIView (QYExpandResponseArea)

- (void)expandResponseAreaBounds:(UIEdgeInsets)outset ; /**< 扩大点击事件的响应区域*/

@end
//  UIView+QYExpandResponseArea.m

#import "UIView+QYExpandResponseArea.h"
#import <objc/runtime.h>

@implementation UIView (QYExpandResponseArea)

+ (void)load {
    //获取替换后的实例方法
    Method newMethod = class_getInstanceMethod([self class], @selector(qy_pointInside:withEvent:));
    //获取替换前的实例方法
    Method origMethod = class_getInstanceMethod([self class], @selector(pointInside:withEvent:));
    //然后交换实例方法
    method_exchangeImplementations(newMethod, origMethod);
}



static char expandSizeKey;
- (void)expandResponseAreaBounds:(UIEdgeInsets)outset{
    //OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    //OBJC_EXPORT 打包lib时,用来说明该函数是暴露给外界调用的。
    //id object 表示关联者,是一个对象
    //id value 表示被关联者,可以理解这个value最后是关联到object上的
    //const void *key 被关联者也许有很多个,所以通过key可以找到指定的那个被关联者
    
    objc_setAssociatedObject(self, &expandSizeKey, [NSValue valueWithUIEdgeInsets:outset], OBJC_ASSOCIATION_COPY_NONATOMIC);
}

//获取设置的扩大size,来扩大button的rect
//当前只是设置了一个扩大的size,当然也可以设置4个扩大的size,上下左右,具体扩大多少对应button的四个边传入对应的size
- (CGRect)expandRect {
    
    NSValue *outsetValue = objc_getAssociatedObject(self, &expandSizeKey);
    UIEdgeInsets outset = outsetValue.UIEdgeInsetsValue;
    //
    if (outsetValue) {
        return CGRectMake(self.bounds.origin.x - outset.left,
                          self.bounds.origin.y - outset.top,
                          self.bounds.size.width + outset.left + outset.right,
                          self.bounds.size.height + outset.top + outset.bottom);
    } else {
        return self.bounds;
    }
}

//响应用户的点击事件
- (BOOL)qy_pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    
    CGRect expandedRect = [self expandRect];
    if (CGRectEqualToRect(expandedRect, self.bounds)) {
        return [self qy_pointInside:point withEvent:event];
    }
    return CGRectContainsPoint(expandedRect, point) ? YES : NO;
}

@end

相关文章

网友评论

      本文标题:利用runtime 扩大UIView的事件响应区域

      本文链接:https://www.haomeiwen.com/subject/ngwefftx.html