問題
一般來說按鈕的點擊范圍和按鈕的大小是相等的,但是如果按鈕很小,就會造成難以點擊的情況,甚至有的時候按鈕周圍還有別的可點擊區域,造成經常誤點擊的差體驗。
一般實現方法
1、設置按鈕的圖片setImage:,然后將按鈕的size設置得比圖片大。
2、在按鈕上面覆蓋一層較大透明的UIView或UIButton,設置點擊事件。
以上兩個方法本身局限性還是比較大的:
1、如果按鈕沒有圖片怎么辦?
2、會改變視圖的層級。
不推薦、比較low。
推薦合理的方法
在WWDC 2012 Session 216視頻中提到的一種解決方式:通過重寫UIButton自身的 -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
方法。
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
//獲取當前button的實際大小
CGRect bounds = self.bounds;
//若原熱區小于44x44,則放大熱區,否則保持原大小不變
CGFloat widthDelta = MAX(44.0 - bounds.size.width, 0);
CGFloat heightDelta = MAX(44.0 - bounds.size.height, 0);
//擴大bounds
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
//如果點擊的點在新的bounds里,就返回YES
return CGRectContainsPoint(bounds, point);
}
Apple的iOS人機交互設計指南中指出,按鈕點擊熱區應不小于44x44pt,否則這個按鈕就會讓用戶覺得“很難用”,所以在這段代碼里,以44為峰值,如果寬度,或高度小于44,就要擴大按鈕的區域,否則保持原有大小。
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
這段代碼應該就是改變bouds的代碼了。后兩個參數是指在左右方向和上下方向擴大或縮小的長度。正值為縮小,負值為擴大。
Demo
效果圖:
圖中,上兩個藍色的正方形就是按鈕,一大一小。綠色的正方形是二者各自可點擊的區域。這里將第一個小按鈕的點擊范圍擴大了,將第二個大按鈕的點擊范圍縮小了。
那么如何得知按鈕點擊的范圍呢?
代碼分析:
第一個按鈕的重寫:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event{
CGRect bounds = self.bounds;
bounds = CGRectInset(bounds, -100, -100);
return CGRectContainsPoint(bounds, point);
}
該按鈕的點擊范圍上下左右同時擴大了100,因此,點擊范圍的寬度 = 按鈕的寬度 + 100*2
;
因此,按鈕的寬度是30,那么點擊范圍的寬度就是230,而且顯然,二者的center應該是同一個。
同理
第二個按鈕的重寫:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
CGRect bounds = self.bounds;
bounds = CGRectInset(bounds, 20, 20);
return CGRectContainsPoint(bounds, point);
}
第二個按鈕的寬度為100,那么它的可點擊寬度就被“縮”成了60(100 - 2*20)
。
為了演示方便,本Demo修改的是正方形按鈕的點擊范圍,而且點擊范圍在橫向和縱向的長度也都是一樣的。當然這種方法同樣可以適用于長方形,而且擴大或縮小的點擊范圍在橫向和縱向的長度也可以不一樣,可自行嘗試。
只要繼承
UIButton
類,重寫這個方法就可以任意改變按鈕的可點擊區域,而且不依賴是否有圖片,也不改變視圖的層級。
注:
通過修改bounds 的x,y 值就可以只向X 軸或者Y軸的某一個方向擴展
當bounds 的X 為0,Y 為負,就只向Y的正方向擴展點擊區域,反之亦然
當bounds 的Y 為0,X 為負,就只向X的正方向擴展點擊區域,反之亦然
如:
CGRect bounds = CGRectMake(0, -70, self.bounds.size.width, self.bounds.size.height);