通過攔截 hitTest:withEvent 方法,解決超出父視圖的子視圖不能接受點擊事件的問題

由于項目需求,我需要在一個高度為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)點擊了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,319評論 25 708
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,614評論 4 61
  • 如果你感到委屈,證明你還有底線 。如果你感到迷茫,證明你還有追求 。如果你感到痛苦,證明你還有力氣 。如果你感到絕...
    伴路閱讀 253評論 0 0
  • 凱文·凱利今年6月又被邀請到TED做演講了,這次他講的題目是“How AI can bring on a seco...
    琢愛舟閱讀 1,891評論 3 8
  • 撥動青春的琴弦 曾經(jīng)帶過一個學(xué)生,少年性格寡默沉靦,不喜與人說話,學(xué)業(yè)成績中等偏下,每天在教室里靜靜的坐著,好像一...
    風(fēng)起123閱讀 479評論 0 1

友情鏈接更多精彩內(nèi)容