www.2527.com_澳门新葡8455手机版_新京葡娱乐场网址_
做最好的网站

www.2527.com追加UIButton的点击范围,三种情势强大

2019-09-10 17:41 来源:未知

背景

在咱们日常生活中,UIButton被用到五颜六色的气象之中。为了体现出其娇小和华美往往都把它做的十分的小也便是给的size十分小。那样固然知足了美观度,可是形成了点击体验效果倒霉的主题材料。(哈哈,因为相似男子手指太粗点不到开关的标题)。

www.2527.com 1斗争的郅博

UI给的图一时候极小,只怕有个需要须求我们扩大button的点击区域, 大家一般的操作是在button 上增添八个view 扩张点击事件,可是大家还会有其余更有助于的办法去扩充button 的点击区域。有亟待能够明白下事件的散发机制。
有三种格局扩张button 的点击区域:

等级:★★☆☆☆标签:「UIButton Runtime」「UIButton点击频率」「UIButton幸免频仍点击」小编: Xs·H审阅核对: QiShare团队

化解情势

1.给UIButton扩充贰个恢弘类(UIButton(Extension)),在在那之中增添如下方法

@implementation UIButton (Extension)@dynamic hitTestEdgeInsets;static const NSString *KEY_HIT_TEST_EDGE_INSETS = @"HitTestEdgeInsets";-setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets { NSValue *value = [NSValue value:&hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)]; objc_setAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}-(UIEdgeInsets)hitTestEdgeInsets { NSValue *value = objc_getAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS); if { UIEdgeInsets edgeInsets; [value getValue:&edgeInsets]; return edgeInsets; }else { return UIEdgeInsetsZero; }}- pointInside:point withEvent:(UIEvent *)event { if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) { return [super pointInside:point withEvent:event]; } CGRect relativeFrame = self.bounds; CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets); return CGRectContainsPoint(hitFrame, point);}@end

2.调用的时候也非常轻易,UIButton对象调hitTestEdgeInsets方法就可以

 UIButton *button = [[UIButton alloc] initWithFrame:CGRectZero];//上下左右的各个方向的Insets量[button setHitTestEdgeInsets:UIEdgeInsetsMake(-10, -10, -10, -10)];[self.view addsubview:button];

注:那样我们点击UIButton附近的上下左右各10的岗位仍是能够触发UIButton点击时间。那样就坚实了充实UIButton的点击范围。

第一种:重写方法 -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event

有多少个实际职业场景必要调控UIButton响应事件的时光距离。比方:1、当通过点击开关来实行网络哀告时,若央浼耗时稍长,客户往往会再点二回。那样,就施行了五遍呼吁,形成了能源浪费。2、在活动终端属性很糟糕时(比如iPhone 6升级到iOS 11),三番两次点击按键会实施多次轩然大波(比如push出来八个viewController)。3、防止暴力点击。

接轨与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);
}
  • 方案 1:通过UIButtonenabled属性和userInteractionEnabled天性决定按键是还是不是可点击。此方案在逻辑上相比较清楚、易懂,但具体代码书写分散,平日提到多个措施。

其次种: 重写方法 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    CGRect rectBig = CGRectInset(self.bounds, -(27.0/2), -(27.0/2));

    if (CGRectContainsPoint(rectBig, point)) {
        return self;
    }else{
        return nil;
    }

    return self;
}
- buttonClicked:(UIButton *)sender { sender.enabled = NO; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ sender.enabled = YES; });}
事实上我们地点所做的转变实在假设留神看点击区域依然个矩形,假设急需大家将点击区域分明在圈子范围 内,大家能够那样做:
-(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);
}
  • 方案2:通过NSObject的 cancelPreviousPerformRequestsWithTarget:selector:object:方法和-performSelector:withObject:afterDelay:艺术调控按键的响应事件的实行时间间隔。此方案会在连接点击按键时裁撤以前的点击事件,从而只进行最后一次点击事件,会产出延迟现象。
- buttonClicked:(UIButton *)sender { [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(buttonClickedAction:) object:sender]; [self performSelector:@selector(buttonClickedAction:) withObject:sender afterDelay:2.0];}

在急需对大气UIButton做决定的气象中,方案1和方案2会相比较不便利。针对此情形,珍视说一下方案3。

  • 方案3:通过Runtime调控UIButton响应事件的时刻间隔。思路如下:1、创造二个UIButton的类别,使用runtimeUIButton增加public属性qi_eventIntervalprivate属性eventUnavailable。2、在 load方法中利用runtimeUIButton-sendAction:to:forEvent:办法与自定义的-qi_sendAction:to:forEvent:措施沟通Implementation。3、使用qi_eventInterval用作调控eventUnavailable的计时因子,用eventUnavailable开控制UIButtonevent事件是还是不是可行。

方案3能够对全体UIButton生效,具体落实代码如下:

@interface UIButton (QiEventInterval)@property (nonatomic, assign) NSTimeInterval qi_eventInterval;@end

#import "UIButton QiEventInterval.h"#import <objc/runtime.h>static char * const qi_eventIntervalKey = "qi_eventIntervalKey";static char * const eventUnavailableKey = "eventUnavailableKey";@interface UIButton ()@property (nonatomic, assign) BOOL eventUnavailable;@end@implementation UIButton (QiEventInterval)  load { Method method = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:)); Method qi_method = class_getInstanceMethod(self, @selector(qi_sendAction:to:forEvent:)); method_exchangeImplementations(method, qi_method);}#pragma mark - Action functions- qi_sendAction:action to:target forEvent:(UIEvent *)event { if (self.eventUnavailable == NO) { self.eventUnavailable = YES; [self qi_sendAction:action to:target forEvent:event]; [self performSelector:@selector(setEventUnavailable:) withObject:@ afterDelay:self.qi_eventInterval]; }}#pragma mark - Setter & Getter functions- (NSTimeInterval)qi_eventInterval { return [objc_getAssociatedObject(self, qi_eventIntervalKey) doubleValue];}- setQi_eventInterval:(NSTimeInterval)qi_eventInterval { objc_setAssociatedObject(self, qi_eventIntervalKey, @(qi_eventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- eventUnavailable { return [objc_getAssociatedObject(self, eventUnavailableKey) boolValue];}- setEventUnavailable:eventUnavailable { objc_setAssociatedObject(self, eventUnavailableKey, @(eventUnavailable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);}@end

选择办法:

UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];/* here is some button's configuration codes */[self.view addSubview:button]; //! 设置按钮的点击响应间隔时间button.qi_eventInterval = 2.0;

成效展现:

  • 默许Button点击效果:

    www.2527.com 2不设置qi_eventInterval

  • 设置qi_eventInterval为2秒:

    www.2527.com 3设置qi_eventInterval为2秒

PS:针对方案3,因为在UIButton QiEventInterval.m中的 load主意中调换了UIControlsendAction:to:forEvent:艺术,所以在应用UIControl或其子类(例如UISlider)的sendAction:to:forEvent:主意时会引起参数缺点和失误的倒台。能够将UIButton QiEventInterval改成UIControl QiEventInterval以幸免此难题。

可从Github获取工程源码

精细入微大家的门道有:QiShareQiShareQiShareQiShareQiShare(CocoaChina)QiShare(StackOverflow)QiShare

推荐小说:iOS UIButton之UIEdgeInsets详解

TAG标签:
版权声明:本文由澳门新葡8455手机版发布于www.2527.com,转载请注明出处:www.2527.com追加UIButton的点击范围,三种情势强大