![](/img/trans.png)
[英]UIButton+Category implementation override other UIButton's touch event
[英]Ignore UIButton's touch event in a long task time
我要忽略長時間運行任務時按鈕的所有觸摸事件。
- (void)buttonAction{
NSLog(@"click!");
button.enabled = NO;
[self longTask];
}
- (void)longTask{
NSLog(@"task begin!");
sleep(5);
NSLog(@"task finished!");
button.enabled = YES;
}
在longTask時間內,我再次單擊該按鈕,實際上什么也沒有發生。 但是,當longTask完成時,它將自動響應單擊事件並再次執行longTask! 當按鈕的啟用值為“否”時,我單擊了多少次,longTask將執行多少次。
2013-08-20 09:24:49.478 AppName[2518:c07] click!
2013-08-20 09:24:49.479 AppName[2518:c07] task begin!
2013-08-20 09:24:54.481 AppName[2518:c07] task finished!
2013-08-20 09:24:54.482 AppName[2518:c07] click!
2013-08-20 09:24:54.482 AppName[2518:c07] task begin!
2013-08-20 09:24:59.484 AppName[2518:c07] task finished!
我試圖將userInteractionEnabled設置為NO,但結果相同。
當長時間執行任務而從不執行任務時,如何使其忽略所有觸摸事件? 換句話說,僅在啟用按鈕值為“是”時單擊按鈕時才執行longTask嗎?
謝謝你的幫助!
sleep
只是凍結了負責所有UI交互的主線程。
您應該在后台執行所有冗長的任務,而使用GCD可以輕松實現這些任務。 只需執行以下操作,您就可以實現所需的功能:
- (void)buttonAction{
NSLog(@"click!");
button.enabled = NO;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
[self longTask];
dispatch_async(dispatch_get_main_queue(), ^(void){
button.enabled = YES;
});
});
}
- (void)longTask{
NSLog(@"task begin!");
[NSThread sleepForTimeInterval:5];
NSLog(@"task finished!");
}
請注意,當您以這種方式進行操作時,將不再阻止所有UI,僅將禁用所需的按鈕。
正如@Erik Godard提到的那樣,您確實應該在執行此類任務時考慮使用某種UI反饋。 您可以在將按鈕的enabled屬性設置為NO
的同一區域中啟動某個過程指示器,並在將該屬性設置為YES
時停止它
沒有GCD的另一種方法是通過NSRunLoop
的方法runUntilDate
更改睡眠。 這樣,您的主線程也不會被阻塞,您將能夠實現所需的功能。
- (void)buttonAction{
NSLog(@"click!");
self.addCartButton.enabled = NO;
[self longTask];
}
- (void)longTask{
NSLog(@"task begin!");
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]];
NSLog(@"task finished!");
self.addCartButton.enabled = YES;
}
兩種方法都經過測試,似乎可行。
這里有幾個問題。
最后,如果您仍然想繼續使用此方法,則可以聲明一個標志,該標志定義是否應調用longTask。 您可以將一個私有實例變量
BOOL shouldCall;
首次調用longTask時,請將其設置為NO。 一旦longTask完成,將其再次更改為yes。 您可以將其與.hidden結合使用以控制按鈕的UI。
正如@LucasEduardo所指出的那樣,除非您擺脫睡眠,否則三分之二的替代方法都不會起作用,因此,請不要理會。
正如@Lucas Eduardo提到的那樣,在后台線程中執行長任務是最好的實現。 但是在某些情況下,該任務必須在主線程中執行,例如發送PDF或Web視圖或移動大圖像。 而且您仍然需要在運行時忽略觸摸事件。
感謝@Erik Godard的觀點。 當我必須在主線程中執行較長的任務時,必須設置BOOL值以響應觸摸事件。
- (void)buttonAction{
NSLog(@"click!");
[self longTask];
}
- (void)longTask{
if (!isRunning) {
button.enabled = NO;
isRunning = YES;
NSLog(@"task begin!");
[NSThread sleepForTimeInterval:5];
NSLog(@"task finished!");
button.enabled = YES;
[self performSelector:@selector(switchStatus) withObject:nil afterDelay:.5f];
}
}
- (void)switchStatus{
isRunning = NO;
}
- (void)viewDidLoad
{
[super viewDidLoad];
isRunning = NO;
}
我在0.5秒的延遲后更改BOOL值,因為如果在button.enabled = YES之后立即設置isRunning = NO,則將再次執行longTask。 只需保留0.5秒的延遲,即可使觸摸事件繼續進行。 在此期間,isRunning的值仍等於YES,因此觸摸事件將被忽略。 0.5秒后,isRunning = NO,如果再次單擊該按鈕將觸發新的longTask。
2013-08-20 20:44:19.727 AppName[4005:c07] click!
2013-08-20 20:44:19.728 AppName[4005:c07] task begin!
2013-08-20 20:44:24.730 AppName[4005:c07] task finished!
2013-08-20 20:44:24.731 AppName[4005:c07] click!
2013-08-20 20:44:24.732 AppName[4005:c07] click!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.