估計很多碼友都遇到過這樣的情況:
UIButton在某些情況下不能立刻響應(yīng)TouchDown事件,換句話說避乏,迅速點擊按鈕時,你是永遠看不見這個按鈕的高亮狀態(tài)的汗捡。
而你會發(fā)現(xiàn)淑际,出現(xiàn)這種情況時畏纲,這些按鈕都在UIScrollView(UITableView)上扇住。
為此我用了一下午時間查貼整理,得到了完美的解決方案盗胀。
在介紹解決方案前艘蹋,必須先科普一些事實,幫助大家理解:
UIScrollView:
1票灰、屬性delaysContentTouches女阀,布爾類型,默認值為YES屑迂。值為YES時浸策,UIScrollView會在接收到手勢時延遲150ms來判斷該手勢是否能夠出發(fā)UIScrollView的滑動事件;值為NO時惹盼,UIScrollView會立馬將接收到的手勢分發(fā)到子視圖上庸汗。
(注:僅僅設(shè)置這個是不夠的,你會發(fā)現(xiàn)如果想要拖動scrollView而起點落在其他有手勢識別的視圖上時會拖不動)
2手报、方法- (BOOL)touchesShouldCancelInContentView:(UIView *)view蚯舱,此方法的重載是幫助我們完美解決問題的重點,決定手勢是否取消傳遞到view上掩蛤,拖動ScrollView時觸發(fā)枉昏。返回NO時,拖動手勢將留在ScrollView上揍鸟,返回YES則將手勢傳到view上兄裂。(若view是UIControl,則默認返回YES)
UITableView:
不得不說,UITableView(包括UITableViewCell在內(nèi))在iOS7和iOS8中的視圖結(jié)構(gòu)是不同的懦窘,且存在著很多我們在編碼時永遠接觸不到的視圖前翎,但我們可通過Debug將其subviews逐個逐個找出來。這關(guān)系到我們這個問題坑比較深的層次畅涂。
iOS7:UITableView中存在n+1個UIScrollView港华,一個是UITableView本身,另外n個存在于UITableViewCell與cell的contentView之間午衰,類名為UITableViewCellScrollView立宜,活的不久,僅存在于iOS7中臊岸,在iOS8中已被移除橙数。
iOS8:UITableView中存在2個UIScrollView,一個是UITableView本身帅戒,另外一個存在于UITableView與UITableViewCell之間灯帮,類名為UITableViewWrapperView。需要注意的是逻住,UITableViewWrapperView在iOS7中并不是一個UIScrollView钟哥。
科普知識完,那么我們就有了以下的問題解決方案了:
1瞎访、將UIButton所有屬于UIScrollView的父視圖的delaysContentTouches屬性設(shè)置成為NO腻贰。
2、繼承UIScrollView或UITableView扒秸,并重寫- (BOOL)touchesShouldCancelInContentView:(UIView*)view方法播演,讓其響應(yīng)拖動方法。
以下是參考代碼:
為了簡便我將兩個類的子類寫在同一個文件中
NoDelayButtonScrollView.h:
import <UIKit/UIKit.h> @interface NoDelayButtonScrollView : UIScrollView @end @interface NoDelayButtonTableView : UITableView @end
NoDelayButtonScrollView.m(1):
import "NoDelayButtonScrollView.h" @implementation NoDelayButtonScrollView - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { self.delaysContentTouches = NO; } return self; } - (BOOL)touchesShouldCancelInContentView:(UIView *)view { if ([view isKindOfClass:[UIButton class]]) { return YES; } return [super touchesShouldCancelInContentView:view]; } @end
NoDelayButtonScrollView.m(2):
@implementation NoDelayButtonTableView - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { self.delaysContentTouches = NO; // iterate over all the UITableView's subviews for (id view in self.subviews) { // looking for a UITableViewWrapperView if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"]) { // this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7 if([view isKindOfClass:[UIScrollView class]]) { // turn OFF delaysContentTouches in the hidden subview UIScrollView *scroll = (UIScrollView *) view; scroll.delaysContentTouches = NO; } break; } } } return self; } - (BOOL)touchesShouldCancelInContentView:(UIView *)view { if ([view isKindOfClass:[UIButton class]]) { return YES; } return [super touchesShouldCancelInContentView:view]; } @end
以上分別對UIScrollView和UITableView進行繼承伴奥,重寫initWithCoder:方法可保證使用Nib文件也能生效
使用這兩個類繼承寫出來的ScrollView和TableView都能快速響應(yīng)子Button的TouchDown事件写烤,并顯示高亮
但以上代碼仍未能解決iOS7下UITableView的子Button高亮延遲問題。
可加入以下代碼來解決:
for (id obj in cell.subviews) { if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"]) { UIScrollView *scroll = (UIScrollView *) obj; scroll.delaysContentTouches = NO; break; } }
這段代碼可加在Custom的UITableViewCell的initWithCoder:方法中拾徙,也可以放在UITableViewDelegate的cellForRowAtIndexPath:方法中設(shè)置對應(yīng)cell中的UITableViewCellScrollView洲炊。
以上,是所有幫助你解決Button延遲高亮問題的方法锣吼。