由于項目需求,我需要在一個高度為50的控件上面創(chuàng)建一個下拉菜單,效果如下

screenshot.png
當(dāng)我做完之后發(fā)現(xiàn),下拉菜單的下拉選擇項不能點擊

screenshot.png
這是因為我們的控件高度只有50,但是下拉菜單的高度超出了控件的大小,這樣,我們就接受不到點擊事件了
這邊找了一個比較詳細(xì)的圖,來描述事件的分發(fā)

226702-dd53b5a6df2f3ea5.png
每個 view 都會有
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *view = [super hitTest:point withEvent:event];
return view;
}
這樣一個方法
這個方法會判斷當(dāng)前點擊的“點”是否在本 view 上,如果在本 view 上,就繼續(xù)尋找本 view 的 Subview,還是通過此方法判斷點擊的“點”是否在 Subview 上,直到找完所有的 Subview,然后這個方法就會 return 這個最終的 Subview 并一層層的向上傳遞給 UIWindow,這樣我們就拿到了屏幕上面最終響應(yīng)的 view。
回到我們最開始遇到的問題。
由于我們下拉菜單超出了我們的自定義控件,當(dāng)我們點擊到下拉菜單時,從 UIWindow 開始通過 hitTest 方法向下尋找響應(yīng)的 view,當(dāng)查找到我們的自定義控件時,就會 return 了,因為我們點擊的“點”已經(jīng)超出了自定義控件,也就是說,這個“點”不在我們的自定義控件上,所以在自定義控件上面的下拉菜單無論如何也不會響應(yīng)。
所以,我們只要手動的去 return 我們的下拉菜單,手動的去連接起這個 響應(yīng) view 的鏈,我們的下拉菜單就能響應(yīng)
- (UIView *)getTargetView:(UIView *)view point:(CGPoint)point event:(UIEvent *)event
{
__block UIView *subView;
//逆序 由層級最低 也就是最上層的子視圖開始
[view.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//point 從view 轉(zhuǎn)到 obj中
CGPoint hitPoint = [obj convertPoint:point fromView:view];
// NSLog(@"%@ - %@",NSStringFromCGPoint(point),NSStringFromCGPoint(hitPoint));
if([obj pointInside:hitPoint withEvent:event])//在當(dāng)前視圖范圍內(nèi)
{
if(obj.subviews.count != 0)
{
//如果有子視圖 遞歸
subView = [self getTargetView:obj point:hitPoint event:event];
if(!subView)
{
//如果沒找到 提交當(dāng)前視圖
subView = obj;
}
}
else
{
subView = obj;
}
*stop = YES;
}
else//不在當(dāng)前視圖范圍內(nèi)
{
if(obj.subviews.count != 0)
{
//如果有子視圖 遞歸
subView = [self getTargetView:obj point:hitPoint event:event];
}
}
}];
return subView;
}
這個方法的目的就是找到點擊的“點”最終所在的 subview,然后 return。
我們再回到我們的響應(yīng)鏈斷掉的地方,也就是自定義控件內(nèi)的 hitTest 方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *view = [super hitTest:point withEvent:event];
//由于響應(yīng)鏈在此處斷開,我們就去手動尋找最終響應(yīng)的子視圖,傳入本 view 遍歷本 view 的子視圖
UIView *tempview = [self getTargetView:self point:point event:event];
if (tempview) {
view = tempview;
}
return view;
}
手動找到點擊的點所在的 subview,并在斷開的地方 return,這樣我們的下拉菜單就能響應(yīng)點擊了