作用:尋找最适合的View
參數:目前手指所在的點.産生的事件
傳回值:傳回誰, 誰就是最适合的View.
什麼時候用調用:隻要一個事件,傳遞給一個控件時, 就會調用這個控件的hitTest方法
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
作用:判斷point在不在方法調用者上
point:必須是方法調用者的坐标系
什麼時候調用:hitTest方法底層會調用這個方法,判斷點在不在控件上.
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return YES;
}
hitTest底層實作:
判斷目前能不能接收事件
if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= )
return nil;
判斷觸摸點在不在目前的控件上
if(![self pointInside:point withEvent:event]) return nil;
從後往前周遊自己的子控件
int count = (int)self.subviews.count;
for (int i = count - ; i >= ;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;
}
}
自己就是最适合的View
return self.
hitTest使用場景一:
業務邏輯:
底部一個按鈕, 按鈕的上面有一個View,遮擋在按鈕的上面.
點選View時, View接收事件,當發現點選的點在按鈕的位置時, 讓底部的按鈕處理事件.
實作思路:
實作View的touchBegain方法,先堅聽UIView的點選.
并去實作UIView的HitTest方法, 在hitTest方法當中通過把目前點轉換成按鈕所在的坐标系
CGPoint btnP = [self convertPoint:point toView:self.btn];
轉換過後檢視目前點在不在按鈕上,如果在按鈕上,就直接傳回按鈕.
如果有在按鈕上,保持系統預設做法.
實作代碼:
-(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];
}
}
hitTest使用場景二:
業務邏輯:
按鈕可以随着手指拖動而拖動.拖動過程當中,按鈕當中的子控件也跟着拖動.
讓超過按鈕的子控件也能夠響應事件,一般情況下,當一個控件超過他的父控件的時候,是不能夠接收事件的.
現在要做的事情就讓超過父控件的按鈕也能夠響應事件.
實作思路:
先辦到讓按鈕能夠跟随着手指移動而移動.
實作按鈕的touchesMoved方法,在touchesMoved方法當中,獲得目前手指所在的點.以前上一個點.
分别計算X軸的偏移量以及Y軸的偏移量.
然後修改目前按鈕的transform讓按鈕辦到能夠跟随着手指移動而移動.
第二步, 實作按鈕的hitTest方法.
在該方法當中去判斷目前的點在不在按鈕的子控件上.
如果在按鈕的子控件上.就傳回按鈕的子控件如果不在的話, 就保持系統的預設做法.
實作代碼:
第一步,讓按鈕能夠跟随着手指移動而移動
-(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);
}
第二步,實作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{如果不在,那麼就保持系統原有做法.
return [super hitTest:point withEvent:event];
}
}