• iOS小技巧:用runtime 解决UIButton 重复点击问题


    http://www.cocoachina.com/ios/20150911/13260.html

    作者:uxyheaven 授权本站转载。

    什么是这个问题

    我们的按钮是点击一次响应一次, 即使频繁的点击也不会出问题, 可是某些场景下还偏偏就是会出问题.

    通常是如何解决

    我们通常会在按钮点击的时候设置这个按钮不可点击. 等待0.xS的延时后,在设置回来; 或者在操作结束的时候设置可以点击.

    1
    2
    3
    4
    5
    6
    - (IBAction)clickBtn1:(UIbutton *)sender
    {
        sender.enabled = NO;
        doSomething
        sender.enabled = YES;
    }

    如果涉及到按钮不同状态不同样式的时候, 用enabled不见得够用.还得额外加个变量来记录状态.

    1
    2
    3
    4
    5
    6
    7
    - (IBAction)clickBtn1:(UIbutton *)sender
    {
        if (doingSomeThing) return;
        doingSomeThing = YES;
        doSomething
        doingSomeThing = NO;
    }

    笔者举的例子是直接在响应事件的周期内直接禁止点击的. 如果想做1秒内禁止重复点击的话,则得用performSelector:withObject:afterDelay:

    漂亮的解决是怎样的

    有了重复的代码段就是有了一个共性, 就可以抽象出来.

    我们可以给按钮添加一个属性重复点击间隔, 通过设置这个属性来控制再次接受点击事件的时间间隔.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @interface UIControl (XY)
    @property (nonatomic, assign) NSTimeInterval uxy_acceptEventInterval;   // 可以用这个给重复点击加间隔
    @end
    static const char *UIControl_acceptEventInterval = "UIControl_acceptEventInterval";
    - (NSTimeInterval)uxy_acceptEventInterval
    {
        return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
    }
    - (void)setUxy_acceptEventInterval:(NSTimeInterval)uxy_acceptEventInterval
    {
        objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(uxy_acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }

    在app启动的时候,我们hook 所有的按钮的 event

    1
    2
    3
    4
    5
    6
    7
    8
    @implementation UIControl (XY)
    + (void)load
    {
        Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
        Method b = class_getInstanceMethod(self, @selector(__uxy_sendAction:to:forEvent:));
        method_exchangeImplementations(a, b);
    }
    @end

    在我们的点击事件里呢,对点击事件做下过滤

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    - (void)__uxy_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
    {
        if (self.uxy_ignoreEvent) return;
        if (self.uxy_acceptEventInterval > 0)
        {
            self.uxy_ignoreEvent = YES;
            [self performSelector:@selector(setUxy_ignoreEvent:) withObject:@(NO) afterDelay:self.uxy_acceptEventInterval];
        }
        [self __uxy_sendAction:action to:target forEvent:event];
    }

    实际使用起来就是这个样子

    1
    2
    3
        UIButton *tempBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        [tempBtn addTarget:self action:@selector(clickWithInterval:) forControlEvents:UIControlEventTouchUpInside];
        tempBtn.uxy_acceptEventInterval = 0.5;

    文章至此就结束了.虽然不推荐大范围用runtime, 但是小范围内使用还是可以解决不少小问题的.

    版权声明:本文为博主原创文章,未经博主允许不得转载。

     
     
  • 相关阅读:
    dp第三题
    近期(2012/5/15)
    HTML5 地理位置定位(HTML5 Geolocation)原理及应用【转】
    xml 中如何正确使用 & 符号
    Python进阶07 函数对象【转】
    Android 快捷小工具
    解决数据库乱码问题【转】
    Android APK反编译详解(附图)
    字符串转日期【20080808080808】
    HTML+5+从入门到精通
  • 原文地址:https://www.cnblogs.com/itlover2013/p/4800235.html
Copyright © 2020-2023  润新知