前言
UI給的圖有時候很小描函,或者有個需求需要我們擴大button的點擊區(qū)域
我們一般的操作是在button 上添加一個view 增加點擊事件印蔬,但是我們還有其他更方便的方法去擴大button 的點擊區(qū)域狼荞。
思考
怎樣來實現(xiàn)這個功能呢派哲?又有多少種方式可以實現(xiàn)呢偎血?下面一一來講霸株。
- 理解事件傳遞過程雕沉,用這個來實現(xiàn)擴大點擊范圍
- 使用Runtime機制擴大點擊范圍
時間傳遞過程
當用戶點擊屏幕后:
UIApplication 先響應事件。
然后傳遞給UIWindow去件。
如果window可以響應坡椒。就開始遍歷window的subviews。遍歷原則是:從離用戶最近的那個子視圖去遍歷
遍歷的過程中尤溜,如果第一個遍歷的view1可以響應倔叼,那就遍歷這個view1的subviews(依次這樣不停地查找,直至查找到合適的響應事件view)宫莱。
如果view1不可以響應丈攒,那就開始對view2進行判斷和子視圖的遍歷。依次類推view3授霸,view4……
如果最后沒有找到合適的響應view巡验,這個消息就會被拋棄。這個就是iOS中的事件鏈碘耳。
如下圖所示:
然而事件的響應鏈條是事件鏈條的逆向显设,根據(jù)視圖層級的添加順序從后往前的
擴大UIButton范圍關鍵的兩個方法:UIView方法
// recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
// default returns YES if point is in bounds
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;
第一種方法
繼承與UIButton,重寫下面的方法:
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
CGRect bounds = self.bounds;
//擴大原熱區(qū)直徑至26辛辨,可以暴露個接口捕捂,用來設置需要擴大的半徑。
CGFloat widthDelta = 26;
CGFloat heightDelta = 26;
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
return CGRectContainsPoint(bounds, point);
}
第二種:重寫方法 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGRect rectRange = CGRectInset(self.bounds, -30.0, -30.0);
if (CGRectContainsPoint(rectRange, point)) {
return self;
}else{
return nil;
}
return self;
}
其實我們上面所做的變化其實如果仔細看點擊區(qū)域還是個矩形斗搞,如果需要我們將點擊區(qū)域規(guī)定在圓形范圍 內指攒,我們可以這樣做:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
[super hitTest:point withEvent:event];
CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
//當然這個半徑也可以擴大
CGFloat raidus = self.frame.size.height >= self.frame.size.width ?self.frame.size.width/2 :self.frame.size.width/2;
//傳入中心點 實時點擊點 與半徑判斷 點擊點是否在半徑區(qū)域內
BOOL pointInRound =[self touchPointInsideCircle:center radius:raidus targetPoint:point];
if (pointInRound) {
return self;
}else
{
return nil;
}
}
//用來判斷 圓形點擊區(qū)域
- (BOOL)touchPointInsideCircle:(CGPoint)center radius:(CGFloat)radius targetPoint:(CGPoint)point {
CGFloat dist = sqrtf((point.x - center.x) * (point.x - center.x) +
(point.y - center.y) * (point.y - center.y));
return (dist <= radius);
}