iOS開發(fā)禁用多個按鈕同時點擊導致誤觸

iOS開發(fā)禁用多個按鈕同時點擊導致誤觸

在開發(fā)iOS項目的時候很多開發(fā)者都不會考慮這樣的一個問題,包括我也不會------一個界面內(nèi)有多個按鈕或者touch事件同時進行會怎么樣?

單從字面上看可能不容易理解,舉個比較容易理解的例子.
在某個應(yīng)用的首頁上,有兩個按鈕,我們單獨的點擊每一個按鈕都會觸發(fā)一次點擊事件,這個本身沒有任何毛病,類似于點擊第一個按鈕跳轉(zhuǎn)到第一個子界面,點擊第二個按鈕跳轉(zhuǎn)到第二個子界面.但是我們是做的移動開發(fā),我們會不會有過這樣的尷尬呢?我們手指比較粗,或者多個手指同事操作, 偶然間的我們會發(fā)生誤觸,導致一個尷尬的場景------兩個按鈕同時點擊了,那么樣的結(jié)果就是,會閃現(xiàn)兩次跳轉(zhuǎn)頁面,即跳轉(zhuǎn)第一個子界面和跳轉(zhuǎn)第二個子界面都會發(fā)生.很顯然這個不是我們想要的.那么怎么屏蔽呢?

1.我們可能會想到禁用按鈕點擊的方式,如果按鈕1點擊了,立刻禁止按鈕2的點擊,事件結(jié)束后開啟按鈕2的點擊,同樣的按鈕2頁做類似的操作,
實驗下來有效么? 不能說完全無效,如果禁止按鈕點擊的代碼已經(jīng)實現(xiàn)了的話.
我們多次嘗試,還是會發(fā)現(xiàn)有誤觸現(xiàn)象.這個方法原理上行得通,但是,真正點擊的時候,你會發(fā)現(xiàn)禁止按鈕點擊的實現(xiàn)和點擊按鈕的事件的先后并不能完全保證...
如果兩次點擊稍微錯開一點點時間差是沒有問題的,但是如果兩次點擊很接近就會出現(xiàn)問題.
如果是這樣的狀態(tài),沒有問題


這里寫圖片描述

但是如果時間段上移一點,則一樣沒有效果


這里寫圖片描述

當然如果你說你可以采用延遲執(zhí)行的方式,保證每次執(zhí)行都會延遲操作,并且做判斷...當然這樣復雜的操作是肯定可以實現(xiàn)的,但是很顯然太復雜了.
那么我們就沒有辦法了嗎?或者我們找找系統(tǒng)方法,看看有沒有能夠?qū)崿F(xiàn)的其他途徑.

2.很顯然,iOS開發(fā)的框架中是有這樣的方法的.


這里寫圖片描述

UIView的UIViewGeometry分類中有這樣的一個屬性.
很顯然,不是遇到這種特殊情況需求的開發(fā)者是很難去有機會了解這個屬性的.
這個屬性很簡單,從翻譯上看:獨家接觸 那么它就一個作用,防止誤觸(同時點擊).當然,它默認是NO,所以我們在開發(fā)中會有誤觸發(fā)生,只要我們設(shè)置為YES即可..

那么我們在開發(fā)中就會多寫一行代碼即可,在創(chuàng)建的時候. 類似于[button setExclusiveTouch:YES]; 或者button.exclusiveTouch = YES;
是的,你已經(jīng)嘗試到了結(jié)果,正是我們想要的,我們不會再發(fā)生那種尷尬的非邏輯上的錯誤發(fā)生了,不懂代碼的老板在拿著你的應(yīng)用最起碼不會因為這個問題而說你不會開發(fā)了(回想剛剛開發(fā)的時候的我.....).

3.有了這么好的方法,我們能夠加以利用呢?很顯然我們在開發(fā)中基本上是不會有同時觸碰的事件居多的,真正需要同時觸碰的基本上應(yīng)該是沒有的(游戲除外...)
我們也都有了解iOS開發(fā)中的runtime機制.我們能否利用這個,將這行代碼給直接寫好呢?
我想到了一個方法.所有的UIView添加到界面上很顯然都會需要這個方法,addSubview:

于是我就想到了創(chuàng)建一個分類,應(yīng)該會好點


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

@implementation UIView (Extension)

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL systemSel = @selector(addSubview:);
        SEL swizzSel = @selector(myAddSubview:);
        Method systemMethod = class_getInstanceMethod([self class], systemSel);
        Method swizzMethod = class_getInstanceMethod([self class], swizzSel);
        BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod));
        if (isAdd) {
            class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));
        }else{
            method_exchangeImplementations(systemMethod, swizzMethod);
        }
    });
}

- (void)myAddSubview:(UIView *)view{
    if ([view respondsToSelector:@selector(setExclusiveTouch:)]) {
        [view setExclusiveTouch:YES];
    }
    [self myAddSubview:view];
}

@end

采用runtime的機制,讓view在被擁有者添加到視圖上的之前先設(shè)置exclusiveTouch屬性.

很顯然,以后我們在寫代碼的時候再也不需要關(guān)心這個了,所有的按鈕,所有的繼承或者來自UIView的都會默認實現(xiàn),我們回顧一下,我們所有能觸發(fā)點擊的控件,有哪一個不是繼承自UIView的呢?

于是乎,我們完美的禁用了多個按鈕同時點擊導致誤觸的尷尬發(fā)生.

3.當然上面的邏輯只是我的一個思路,我們也可以采用遍歷的方式啊
我們替換VC中viewDidAppear:的方法

#import "UIViewController+Extension.h"

@implementation UIViewController (Extension)

+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        
        SEL originalSelector = @selector(viewDidAppear:);
        SEL swizzledSelector = @selector(myViewDidAppear:);
        
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        if (success) {
            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

-(void)myViewDidAppear:(BOOL)animated{
    for (UIView * subview in self.view.subviews) {
        if ([subview respondsToSelector:@selector(setExclusiveTouch:)]) {
            [subview setExclusiveTouch:YES];
        }
    }
    [self myViewDidAppear:animated];
}

@end

在viewController顯示到屏幕的時候在viewDidAppear:中遍歷子視圖,當然子視圖中是否有子視圖?這個是否也需要遍歷?這里也是需要開發(fā)者自己考慮的,是深度遍歷,還是廣度遍歷...這些都不在本博客討論范圍內(nèi)...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評論 25 708
  • 本文屬于原創(chuàng)文章。轉(zhuǎn)載請聯(lián)系作者。本文首發(fā)地址:http://m.itdecent.cn/p/0c913719...
    酷酷的哀殿閱讀 1,069評論 0 5
  • 攝影是述說內(nèi)心的方式。當文字不足以表述時空時,它可以生動描述并引起共鳴。我攝影純粹表現(xiàn)內(nèi)心世界,所以是自我的。大家...
    每日愛圖閱讀 110評論 0 0
  • 提煉:解決沖突 采取共贏,而不是你贏我輸,我贏你輸。 解決過程: 一,界定問題 二,想出可能的解決方案 三,評估所...
    egomuff閱讀 165評論 0 0
  • ROS采用rosrun命令可以啟動一個節(jié)點,如果需要同時啟動節(jié)點管理器(master)和多個節(jié)點,就需要采用lau...
    marine0131閱讀 12,506評論 0 0

友情鏈接更多精彩內(nèi)容