iOS-TabBar中間凸起點擊完全有反應

  • 先看下效果
仿閑魚.png
  • 為什么還要繼續說這個內容呢?
  • 前一段微博上很火的tabbar封裝大賽想必大家都知道吧,各位大神盡其所能
  • 自己正在仿寫閑魚,看了網上一些朋友寫的關于tabbar中間按鈕的處理,發現關于處理中間按鈕的點擊這塊有點模糊
  • 個人估計是大家在寫這一塊的時候忽略了這個細節
    • 有的是中間按鈕凸起的部分點擊沒有反應,按鈕其他地方可以點擊
    • 有的是中間凸起按鈕可以完全點擊了,但是沒有做細節處理,導致push到其他頁面,在和凸起按鈕同樣的位置還可以被點擊,而且點擊效果和點擊凸起按鈕效果是一樣的
    • 還有的是雖然實現了功能,但是處理方法上并不是很完善
因此決定熬夜寫下這篇文章,幫助有需要的朋友看一下
  • 突然感覺沒有什么可說的了,哈哈,主要是我代碼里面已經寫得非常詳細了,而且文字多了效果也不好

  • 簡單的說下大致結構和思路吧

  • tabbar的話也是遵循主流,自定義一個繼承自系統UITabbar的LBTabbar,然后用KVC和系統的進行替換

  • 中間的凸起按鈕和tabbar內部的子控件不是同一類型,是一個UIButton而已

  • 根據tabbar內部子控件的類型去調整內部子控件的位置,從而騰出一個中間位置給凸起按鈕

  • 給tabbar弄一個代理,添加一個點擊中間凸起按鈕的代理方法,讓LBTabBarController成為它的代理,實現對應代理方法即可實現按鈕點擊

  • 如果對以上步驟有不清楚的地方可以看代碼或者隨時咨詢我哦,這篇文字主要講的核心就是中間按鈕點擊
    1)要想監聽整個發布按鈕的點擊,包括凸起部分點擊也有反應,那么我是通過在自定義的LBTabbar內部重寫- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)even方法來實現的
    2)我們都知道,凸起按鈕是自定義的LBTabbar的子控件,默認情況下子控件尺寸如果超出父控件,那么超出的部分點擊是沒有反應的
    3)hitTest這個方法就是專門返回一個處理響應事件最合適view的,一般情況下我們不實現這個方法,默認就是讓系統幫我們去判斷處理事件響應最合適的view,一旦我們想要改變一下這種情況,我們就需要通過重寫這個方法
    4)我們的需求是只要我們點擊的point在凸起按鈕的任何位置(無論是否超出tabbar)都可以有響應,那么我們首先需要判斷這個point是否在凸起按鈕自身上
    [self convertPoint:point toView:self.plusBtn]
    這句代碼就是將當前tabbar的觸摸點轉換坐標系,轉換到凸起按鈕的身上,它會生成一個新的點,然后我們通過
    [self.plusBtn pointInside:newP withEvent:event]方法判斷如果這個新的點是在發布按鈕身上,那么處理點擊事件最合適的view就是發布按鈕,否則直接讓系統幫我們處理點擊事件就可以了
    5)對了,這里還有一步也是非常關鍵,因為我們重寫了尋找最合適view的方法,那么我們還需要考慮什么情況下我們需要由我們自己選擇最合適的view,什么情況下不需要,所以我們需要加一個判斷if (self.isHidden == NO)
    這句代碼代表了當前頁面是有tabbar的,那么肯定是在導航控制器的根控制器頁面,這個時候就需要由我們自己選擇最合適的view,其他的push頁面直接讓系統選擇
    6)如果不做第五步判斷,bug就是由導航控制器的根控制器頁面push到其他頁面后,點擊該頁面和tabbar凸起按鈕同樣的位置也會有反應
    7)好了,該上關鍵代碼了

//重寫hitTest方法,去監聽發布按鈕的點擊,目的是為了讓凸出的部分點擊也有反應
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    //這一個判斷是關鍵,不判斷的話push到其他頁面,點擊發布按鈕的位置也是會有反應的,這樣就不好了
    //self.isHidden == NO 說明當前頁面是有tabbar的,那么肯定是在導航控制器的根控制器頁面
    //在導航控制器根控制器頁面,那么我們就需要判斷手指點擊的位置是否在發布按鈕身上
    //是的話讓發布按鈕自己處理點擊事件,不是的話讓系統去處理點擊事件就可以了
    if (self.isHidden == NO) {

        //將當前tabbar的觸摸點轉換坐標系,轉換到發布按鈕的身上,生成一個新的點
        CGPoint newP = [self convertPoint:point toView:self.plusBtn];

        //判斷如果這個新的點是在發布按鈕身上,那么處理點擊事件最合適的view就是發布按鈕
        if ( [self.plusBtn pointInside:newP withEvent:event]) {
            return self.plusBtn;
        }else{//如果點不在發布按鈕身上,直接讓系統處理就可以了
          return [super hitTest:point withEvent:event];
     }
   } 
    else {//tabbar隱藏了,那么說明已經push到其他的頁面了,這個時候還是讓系統去判斷最合適的view處理就好了
        return [super hitTest:point withEvent:event];
    }
}
下面是排布tabbar里面的子控件的
- (void)layoutSubviews
{
    [super layoutSubviews];
    //系統自帶的按鈕類型是UITabBarButton,找出這些類型的按鈕,然后重新排布位置,空出中間的位置
    Class class = NSClassFromString(@"UITabBarButton");

    self.plusBtn.size = CGSizeMake(self.plusBtn.currentBackgroundImage.size.width, self.plusBtn.currentBackgroundImage.size.height);

    self.plusBtn.centerX = self.centerX;
    //調整發布按鈕的中線點Y值
    self.plusBtn.centerY = self.height * 0.5 - 2*LBMagin ;


        UILabel *label = [[UILabel alloc] init];
        label.text = @"發布";
        label.font = [UIFont systemFontOfSize:11];
        [label sizeToFit];
        label.textColor = [UIColor grayColor];
        [self addSubview:label];
        label.centerX = self.plusBtn.centerX;
        label.centerY = CGRectGetMaxY(self.plusBtn.frame) + LBMagin ;



    int btnIndex = 0;
    for (UIView *btn in self.subviews) {//遍歷tabbar的子控件
        if ([btn isKindOfClass:class]) {//如果是系統的UITabBarButton,那么就調整子控件位置,空出中間位置
            //每一個按鈕的寬度==tabbar的五分之一
            btn.width = self.width / 5;

            btn.x = btn.width * btnIndex;

            btnIndex++;
            //如果是索引是2(從0開始的),直接讓索引++,目的就是讓消息按鈕的位置向右移動,空出來發布按鈕的位置
            if (btnIndex == 2) {
                btnIndex++;
            }
            
        }
    }
}

  • OK,結束了,不足之處歡迎大家指正,共同學習
    代碼地址
后續準備寫一篇關于事件響應和傳遞的文章,如果對于hitTest方法不是很熟悉的朋友可以后續看看,個人感覺這塊也是面試常客,感謝支持
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容