hitTest
- 作用:尋找最適合的View
參數(shù):當前手指所在的點.產(chǎn)生的事件
返回值:返回誰, 誰就是最適合的View.
什么時候用調(diào)用:只要一個事件,傳遞給一個控件時, 就會調(diào)用這個控件的hitTest方法
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
PointInside
- 作用:判斷point在不在方法調(diào)用者上
point:必須是方法調(diào)用者的坐標系
什么時候調(diào)用:hitTest方法底層會調(diào)用這個方法,判斷點在不在控件上.
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return YES;
}
hitTest底層實現(xiàn):
- 1.判斷當前能不能接收事件
if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01)
return nil;
- 2.判斷觸摸點在不在當前的控件上
if(![self pointInside:point withEvent:event]) return nil;
- 3.從后往前遍歷自己的子控件
int count = (int)self.subviews.count;
for (int i = count - 1; i >= 0;i-- ) {
UIView *childV = self.subviews[i];
// 把當前坐標系上的點轉換成子控件坐標系上的點.
CGPoint childP = [self convertPoint:point toView:childV];
判斷自己的子控件是不是最適合的View
UIView *fitView = [childV hitTest:childP withEvent:event];
如果子控件是最適拿的View,直接返回
if (fitView) {
return fitView;
}
}
- 4.自己就是最適合的View
return self.
練習1
業(yè)務邏輯:
底部一個按鈕, 按鈕的上面有一個View,遮擋在按鈕的上面.
點擊View時, View接收事件,當發(fā)現(xiàn)點擊的點在按鈕的位置時, 讓底部的按鈕處理事件.實現(xiàn)思路:
實現(xiàn)View的touchBegain方法,先監(jiān)聽UIView的點擊.
并去實現(xiàn)UIView的HitTest方法, 在hitTest方法當中通過把當前點轉換成按鈕所在的坐標系
CGPoint btnP = [self convertPoint:point toView:self.btn];
轉換過后查看當前點在不在按鈕上,如果在按鈕上,就直接返回按鈕.
如果有在按鈕上,保持系統(tǒng)默認做法.實現(xiàn)代碼:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
判斷當前點在不在按鈕上.
把當前點轉換成按鈕所在的坐標系
CGPoint btnP = [self convertPoint:point toView:self.btn];
if ([self.btn pointInside:btnP withEvent:event]) {
return self.btn;
}else{
return [super hitTest:point withEvent:event];
}
}
練習2
業(yè)務邏輯:
按鈕可以隨著手指拖動而拖動.拖動過程當中,按鈕當中的子控件也跟著拖動.
讓超過按鈕的子控件也能夠響應事件,一般情況下,當一個控件超過他的父控件的時候,是不能夠接收事件的.
現(xiàn)在要做的事情就讓超過父控件的按鈕也能夠響應事件.-
實現(xiàn)思路:
先辦到讓按鈕能夠跟隨著手指移動而移動.
實現(xiàn)按鈕的touchesMoved方法,在touchesMoved方法當中,獲得當前手指所在的點.以前上一個點.
分別計算X軸的偏移量以及Y軸的偏移量.
然后修改當前按鈕的transform讓按鈕辦到能夠跟隨著手指移動而移動.第二步, 實現(xiàn)按鈕的hitTest方法.
在該方法當中去判斷當前的點在不在按鈕的子控件上.
如果在按鈕的子控件上.就返回按鈕的子控件如果不在的話, 就保持系統(tǒng)的默認做法.
實現(xiàn)代碼:
第一步,讓按鈕能夠跟隨著手指移動而移動
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
獲取當前的手指
UITouch *touch = [touches anyObject];
獲取當前手指所在的點
CGPoint curP = [touch locationInView:self];
獲取當前手指的上一個點
CGPoint preP = [touch previousLocationInView:self];
計算X軸的偏移量
CGFloat offsetX = curP.x - preP.x;
計算Y軸的偏移量
CGFloat offsetY = curP.y - preP.y;
修改按鈕的形變,讓按鈕能夠移動.
self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);
}
- 第二步,實現(xiàn)hitTest方法,判斷手指當前所在的點在不在按鈕的子控件上.
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
把當前所在的點轉換成按鈕子控件上面的點
CGPoint chatP = [self convertPoint:point toView:self.chatBtn];
判斷轉換后的點在不在按鈕的控件上.
if ([self.chatBtn pointInside:chatP withEvent:event]) {如果在
直接返回,也就意味著,當前最適合的View,就是這個按鈕
return self.chatBtn;
}else{如果不在,那么就保持系統(tǒng)原有做法.
return [super hitTest:point withEvent:event];
}
}