UIButton

329 阅读2分钟

扩大点击范围:

1、在 button 上添加一个view 增加点击事件

2、继承UIButton,实现如下效果:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
    CGRect bounds = self.bounds;
    //扩大原热区直径至26,可以暴露个接口,用来设置需要扩大的半径。
    CGFloat widthDelta = MAX(26, 0);
    CGFloat heightDelta = MAX(26, 0);
    bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
    return CGRectContainsPoint(bounds, point);
}

3、在这个 Button 的 superview 里,重写 hitTest: 方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    CGRect rectBig = CGRectInset(self.bounds, -(27.0/2), -(27.0/2));
    if (CGRectContainsPoint(rectBig, point)) {
        return button;
    }
    return [super hitTest:point withEvent:event];
}

点击区域规定在圆形范围

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    [super hitTest:point withEvent:event];
    CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
    
   // 当然这个半径也可以扩大
    CGFloat raidus = self.frame.size.height >= self.frame.size.width ? self.frame.size.width/2 :self.frame.size.width/2;
    
   // 传入中心点 实时点击点 与半径判断 点击点是否在半径区域内
    BOOL pointInRound = [self touchPointInsideCircle:center radius:raidus targetPoint:point];
    
    if (pointInRound) {
        return self;
    } else {
        return nil;
    }
}
// 用来判断 圆形点击区域
- (BOOL)touchPointInsideCircle:(CGPoint)center radius:(CGFloat)radius targetPoint:(CGPoint)point {
    CGFloat dist = sqrtf((point.x - center.x) * (point.x - center.x) + (point.y - center.y) * (point.y - center.y));
    return (dist <= radius);
}

4、UIButton 分类

@interface UIButton (EnlargeEdge)

/** 设置可点击范围到按钮边缘的距离 */
- (void)setEnlargeEdge:(CGFloat)size;

/** 设置可点击范围到按钮上、右、下、左的距离 */
- (void)setEnlargeEdgeWithTop:(CGFloat)top right:(CGFloat)right bottom:(CGFloat)bottom left:(CGFloat)left;

@end

#import "UIButton+EnlargeEdge.h"
#import <objc/runtime.h>
static char topNameKey;
static char rightNameKey;
static char bottomNameKey;
static char leftNameKey;

@implementation UIButton (EnlargeEdge)

- (void)setEnlargeEdge:(CGFloat)size {
    objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:size], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:size], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:size], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:size], OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (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);
}

- (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;
    }
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGRect rect = [self enlargedRect];
    if (CGRectEqualToRect(rect, self.bounds)) {
        return [super pointInside:point withEvent:event];
    }
    return CGRectContainsPoint(rect, point) ? YES : NO;
}

@end

增加UIButton点击间隔:

#import <UIKit/UIKit.h>

@interface UIControl (FMGControl)
@property (assign, nonatomic) NSTimeInterval acceptEventInterval;

@end
#import "UIControl+FMGControl.h"
#import <objc/runtime.h>
static const char *UIControl_acceptEventInterval = "UIControl_acceptEventInterval";

@implementation UIControl (FMGControl)
- (NSTimeInterval)acceptEventInterval {
    return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
}

- (void)setAcceptEventInterval:(NSTimeInterval)acceptEventInterval {
    objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)FMG_ignoreEvent {
    return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
}

+ (void)load {
    Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
    Method b = class_getInstanceMethod(self, @selector(FMG_sendAction:to:froEvent:));
    method_exchangeImplementations(a, b);
}

- (void)FMG_sendAction:(SEL)action to:(id)target froEvent:(UIEvent *)event {
    if (self.acceptEventInterval > 0) {
        if (self.userInteractionEnabled) {
            [self FMG_sendAction:action to:target froEvent:event];
        }
        self.userInteractionEnabled = NO;
        [self performSelector:@selector(setUserInteractionEnabled:) withObject:@(YES) afterDelay:self.acceptEventInterval];
        
        // GCD 延迟执行 self.acceptEventInterval:为延迟时间
        __weak typeof (self) weakSelf = self;
        dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.acceptEventInterval * NSEC_PER_SEC));
        dispatch_after(delayTime, dispatch_get_main_queue(), ^{
            weakSelf.userInteractionEnabled = YES;
        });
    } else {
        [self FMG_sendAction:action to:target froEvent:event];
    }
}

@end