iOS7/8 UIButton高亮狀態延遲有關問題全解
阿新 • • 發佈:2019-01-11
iOS7/8 UIButton高亮狀態延遲問題全解
為此我用了一下午時間查貼整理,得到了完美的解決方案。
在介紹解決方案前,必須先科普一些事實,幫助大家理解:
UIScrollView:
1、屬性 delaysContentTouches ,布林型別,預設值為YES。值為YES時,UIScrollView會在接收到手勢時延遲150ms來判斷該手勢是否能夠出發UIScrollView的滑動事件;值為NO時,UIScrollView會立馬將接收到的手勢分發到子檢視上。
(注:僅僅設定這個是不夠的,你會發現如果想要拖動scrollView而起點落在其他有手勢識別的檢視上時會拖不動)
2、方法 - (BOOL)touchesShouldCancelInContentView:(UIView *)view ,此方法的過載是幫助我們完美解決問題的重點,決定手勢是否取消傳遞到view上,拖動ScrollView時觸發。返回NO時,拖動手勢將留在ScrollView上,返回YES則將手勢傳到view上。(若view是UIControl,則預設返回YES)
UITableView:
不得不說,UITableView(包括UITableViewCell在內)在iOS7和iOS8中
的檢視結構是不同的,且存在著很多我們在編碼時永遠接觸不到的檢視,但我們可通過Debug將其subviews逐個逐個找出來。這關係到我們這個問題坑比較深的層次。
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 屬性設定成為NO。
2、繼承UIScrollView或UITableView,並重寫 - ( BOOL )touchesShouldCancelInContentView:( UIView *)view 方法,讓其響應拖動方法。
以下是參考程式碼:
為了簡便我將兩個類的子類寫在同一個檔案中
NoDelayButtonScrollView.m(1):
NoDelayButtonScrollView.m(2):
以上分別對UIScrollView和UITableView進行繼承,重寫initWithCoder:方法可保證使用Nib檔案也能生效
使用這兩個類繼承寫出來的ScrollView和TableView都能快速響應子Button的TouchDown事件,並顯示高亮
但以上程式碼仍未能解決iOS7下UITableView的子Button高亮延遲問題。
可加入以下程式碼來解決:
這段程式碼可加在Custom的UITableViewCell的initWithCoder:方法中,也可以放在UITableViewDelegate的cellForRowAtIndexPath:方法中設定對應cell中的UITableViewCellScrollView。
以上,是所有幫助你解決Button延遲高亮問題的方法。
估計很多碼友都遇到過這樣的情況:
UIButton在某些情況下不能立刻響應TouchDown事件,換句話說,迅速點選按鈕時,你是永遠看不見這個按鈕的高亮狀態的。
而你會發現,出現這種情況時,這些按鈕都在UIScrollView(UITableView)上。為此我用了一下午時間查貼整理,得到了完美的解決方案。
在介紹解決方案前,必須先科普一些事實,幫助大家理解:
UIScrollView:
1、屬性 delaysContentTouches ,布林型別,預設值為YES。值為YES時,UIScrollView會在接收到手勢時延遲150ms來判斷該手勢是否能夠出發UIScrollView的滑動事件;值為NO時,UIScrollView會立馬將接收到的手勢分發到子檢視上。
(注:僅僅設定這個是不夠的,你會發現如果想要拖動scrollView而起點落在其他有手勢識別的檢視上時會拖不動)
2、方法 - (BOOL)touchesShouldCancelInContentView:(UIView *)view ,此方法的過載是幫助我們完美解決問題的重點,決定手勢是否取消傳遞到view上,拖動ScrollView時觸發。返回NO時,拖動手勢將留在ScrollView上,返回YES則將手勢傳到view上。(若view是UIControl,則預設返回YES)
UITableView:
不得不說,UITableView(包括UITableViewCell在內)在iOS7和iOS8中
iOS7:UITableView中存在n+1個UIScrollView,一個是UITableView本身,另外n個存在於UITableViewCell與cell的contentView之間,類名為UITableViewCellScrollView,活的不久,僅存在於iOS7中,在iOS8中已被移除。
iOS8:UITableView中存在2個UIScrollView,一個是UITableView本身,另外一個存在於UITableView與UITableViewCell之間
科普知識完,那麼我們就有了以下的問題解決方案了:
1、將UIButton所有屬於UIScrollView的父檢視的 delaysContentTouches 屬性設定成為NO。
2、繼承UIScrollView或UITableView,並重寫 - ( BOOL )touchesShouldCancelInContentView:( UIView *)view 方法,讓其響應拖動方法。
以下是參考程式碼:
為了簡便我將兩個類的子類寫在同一個檔案中
NoDelayButtonScrollView.h:
[objc] view plain copy
- #import <UIKit/UIKit.h>
- @interface NoDelayButtonScrollView : UIScrollView
- @end
- @interface NoDelayButtonTableView : UITableView
- @end
NoDelayButtonScrollView.m(1):
[objc] view plain copy
- #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):
[objc] view plain copy
- @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都能快速響應子Button的TouchDown事件,並顯示高亮
但以上程式碼仍未能解決iOS7下UITableView的子Button高亮延遲問題。
可加入以下程式碼來解決:
[objc] view plain copy
- 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:方法中設定對應cell中的UITableViewCellScrollView。
以上,是所有幫助你解決Button延遲高亮問題的方法。