美文网首页
iOS开发小记:运用Runtime机制扩大UIButton的响

iOS开发小记:运用Runtime机制扩大UIButton的响

作者: 我消失1314 | 来源:发表于2017-04-26 17:28 被阅读56次

    转载自 iOS开发小记:运用Runtime机制扩大UIButton的响应区域

    版权声明:本文为博主原创文章,未经博主允许不得转载。      Hello大家好,我是李永乐。      在iOS开发中,有时会将一个UIButton的外观设置成很小,从而使其点按操作变得很不容易,因为点按的区域是根据UIButton的frame决定的。解决这个问题的办法一般是把button的frame放大,然后把里面的内容缩小,但是这样做总是感觉不伦不类,还需要分别重新调整Button的frame和显示内容的frame,比较麻烦。今天笔者在外国网站总结了一种方法,通过OC创建类别的方式,运用Runtime关联对象的方法,对UIButton进行了扩展 ,创建一个方法直接用于扩大Button的点按区域,而不改变它的显示内容,使代码的可读性大大增强。      其执行原理为:OC中创建类别(Categroy)的方式,并不允许给已有的类扩展属性,只可以给其扩展方法。所以,需要使用Runtime“黑魔法”中的关联对象(Associative Object)的一些方法,动态地为某个button对象添加扩展距离的属性,然后检测UITouch事件的触摸点是否在我们扩展距离后Rect内,从而达到想要的效果。      首先,创建一个UIButton的Category,起名为EnlargeTouchArea,设置一个外界可访问的方法setEnlaEdgeWithTop:right:bottom:left,在使用时也只需使用这个方法即可,传入的四个参数分别是上、右、下、左的扩展距离。[objc] view plain copy//  UIButton+EnlargeTouchArea.h    #import#import@interface UIButton (EnlargeTouchArea)    - (void)setEnlargeEdgeWithTop:(CGFloat) top right:(CGFloat) right bottom:(CGFloat) bottom left:(CGFloat) left;    @end          然后导入,所有Runtime的黑魔法都在这里[objc] view plain copy//  UIButton+EnlargeTouchArea.m    #import "UIButton+EnlargeTouchArea.h"    #import@implementation UIButton (EnlargeTouchArea)

    static char topNameKey;

    static char rightNameKey;

    static char bottomNameKey;

    static char leftNameKey;

    objc_setAssociatedObject是一个C语言函数,这个函数被称之为“关联API”,它的作用是把top、right、bottom、left这四个从外界获取到的值与本类(self)关联起来,然后设置一个static char作为能够找到他们的Key

    [objc] view plain copy

    - (void) setEnlargeEdgeWithTop:(CGFloat) top right:(CGFloat) right bottom:(CGFloat) bottom left:(CGFloat) left

    {

    objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);

    objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);

    objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC);

    objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);

    }

    objc_getAssociatedObject同样也是一个关联API(c语言函数),它可以通过刚刚设置的Key找到上个方法中从外界传入的top、right、bottom、left,这个api和obj_setAssociatedObject一起使用就可以达到给已有类扩展属性的效果。最后我们通过self.bounds设置一个新的CGRect,作为扩大后的点按区域,并且返回

    [objc] view plain copy

    - (CGRect) enlargedRect

    {

    NSNumber* topEdge = objc_getAssociatedObject(self, &topNameKey);

    NSNumber* rightEdge = objc_getAssociatedObject(self, &rightNameKey);

    NSNumber* bottomEdge = objc_getAssociatedObject(self, &bottomNameKey);

    NSNumber* leftEdge = objc_getAssociatedObject(self, &leftNameKey);

    if (topEdge && rightEdge && bottomEdge && leftEdge)

    {

    return CGRectMake(self.bounds.origin.x - leftEdge.floatValue,

    self.bounds.origin.y - topEdge.floatValue,

    self.bounds.size.width + leftEdge.floatValue + rightEdge.floatValue,

    self.bounds.size.height + topEdge.floatValue + bottomEdge.floatValue);

    }

    else

    {

    return self.bounds;

    }

    }

    这个方法UIView的一个实例方法,作用是,捕获当前的UITouch事件中的触摸点,检测它是否在最上层的子视图内,如果不是的话就递归检测其父视图。这样的话,我们就只是将当前某一个触摸的point与某一个rect进行比较,并没有改变Button真实的frame,从而真正的从逻辑上达到了只是扩大点按区域的效果。

    [objc] view plain copy

    - (UIView*) hitTest:(CGPoint) point withEvent:(UIEvent*) event

    {

    CGRect rect = [self enlargedRect];

    if (CGRectEqualToRect(rect, self.bounds))

    {

    return [super hitTest:point withEvent:event];

    }

    return CGRectContainsPoint(rect, point) ? self : nil;

    }

    总结一下,为什么要用runtime去为已有类达到一个扩展属性的效果呢,正是因为上面这个方法,这个系统提供的方法并没有提供接受其他参数的地方,而我们却必须要指定一个扩大的区域作为参数,所以就必须为这个类扩展一个新的属性。

    相关文章

      网友评论

          本文标题: iOS开发小记:运用Runtime机制扩大UIButton的响

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