iOS 自定義 Tabbar 樣式設(shè)計(jì) 及 按鈕事件熱區(qū)修改

一、需求背景

現(xiàn)在越來越多的應(yīng)用追求個(gè)性化的頁(yè)面風(fēng)格,類似下圖的UI設(shè)計(jì),原生的tabbar已經(jīng)不能滿足應(yīng)用的需求,那么我們就需要對(duì)tabbar 進(jìn)行自定義處理了。

截屏2020-03-03下午4.25.51.png

那么如何才能達(dá)到這種設(shè)計(jì)需求呢

1、自定義一個(gè)類繼承至 UITabBar

@interface BaseTabbar : UITabBar

2、重寫B(tài)aseTabbar layoutSubviews方法

- (void)layoutSubviews {
    [super layoutSubviews];
    TSUser *user = [TSUser currentUser];
    TSNationConfigModel *config = [TSNationConfigModel currentConfig];
    if (config.enabled_sns && config.enabled_sns_user_content && user.user_level == 20) {
        CGFloat index = 0;
        //每個(gè)item的寬高
        CGFloat w = self.width / (self.subviews.count+1);
        CGFloat h = self.height;
        //設(shè)置中間 按鈕 publishButton的frame(-40 設(shè)置發(fā)布按鈕向上偏移量 )
        self.publishButton.frame = CGRectMake(2 * w, -40 , w, h+50);
        for (UIView *button in self.subviews) {
          if ([button isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
              //跳過中間 按鈕
              if (index == 2)  index = 3;
                 button.frame = CGRectMake(index * w, 0, w, h);
                 index ++;
             }
         }
     }
}

3、到此自定義UITabBar布局已經(jīng)完成 ,接下來最關(guān)鍵一步要即將上演, 那就是 通過KVC 將UITabBarController控制器中自帶的的tabBar 替換成 我們自定義完成的BaseTabbar。

BaseTabbar *customTabBar = [[BaseTabbar alloc]init]
//使用KVC重設(shè)tabBar
 [self setValue:customTabBar forKey:@"tabBar"];

至此 自定義的Tabbar已經(jīng)創(chuàng)建成功,快去看看是不是已經(jīng)是符合產(chǎn)品需求的布局吧,大老爺你以為到此就結(jié)束了嗎,當(dāng)然還有請(qǐng)繼續(xù)往下看。。。

二、中間按鈕 超出 UITabBar(見圖一 按鈕3部分)不響應(yīng)事件問題處理

父視圖是圖中藍(lán)色框大小,中間按鈕凸起部分在視圖外,在這種情況下如果我們不做任何處理,點(diǎn)擊圖中紅色區(qū)域是無法被響應(yīng)的。

響應(yīng)鏈在這里就不過多介紹了,我們主要介紹事件分發(fā)時(shí)是如何找到最合適的事件處理者。
這里需要了解兩個(gè)方法:

// 判斷點(diǎn)擊區(qū)域是否在當(dāng)前視圖范圍內(nèi)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
// 最適合處理事件的試圖
View- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

方法一用于判斷點(diǎn)擊區(qū)域是否在當(dāng)前視圖范圍內(nèi)
方法二用于尋找最適合的View

我們以上圖的例子進(jìn)行說明,暫時(shí)稱呼它為tabbar,其視圖范圍為圖中1區(qū)域,中間凸起部分button在視圖外的部分為2區(qū)域,兩者重合部分為3區(qū)域。
在點(diǎn)擊1、2、3區(qū)域時(shí)都會(huì)先調(diào)用tabbar的- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event,只不過返回值不同,結(jié)果不同,我們?cè)敿?xì)來看看會(huì)發(fā)生什么。

1.1、點(diǎn)擊區(qū)域 -> 1

tabbar的方法一返回YES,接著會(huì)去遍歷tabbar上所有子控件并調(diào)用子控件中的方法一,也就是會(huì)調(diào)用button的方法一,由于button不在1區(qū)域內(nèi),所以button的方法一返回NO,并且button的方法二返回null,然后調(diào)用tabbar的方法二并返回self即tabbar本身處理點(diǎn)擊事件。

2013977-9e08ba1bbbce13ed.jpeg

1.2、點(diǎn)擊區(qū)域 -> 2

tabbar的方法一返回YES,接著會(huì)去遍歷tabbar上所有子控件并調(diào)用子控件中的方法一,也就是會(huì)調(diào)用button的方法一,所以button的方法一返回YES,并且button的方法二返回本身,然后調(diào)用tabbar的方法二并返回button,最終由button處理點(diǎn)擊事件。

2013977-9eb024566ab3a575.jpeg

1.3、點(diǎn)擊區(qū)域 -> 3

我們?cè)谧远xtabbar時(shí),一般有兩種方式:
1、將自定義的tabbar添加到原來的tabbar上。
2、利用KVC替換掉原來的tabbar。

方式一
事件分發(fā)是由下往上進(jìn)行分發(fā),在調(diào)用系統(tǒng)tabbar方法一的時(shí)候,返回值為NO,事件不會(huì)繼續(xù)向上分發(fā),即不會(huì)調(diào)用自定義的tabbar的那兩個(gè)方法,由系統(tǒng)的tabbar成為事件的接收者。此時(shí)無法實(shí)現(xiàn)我們的需求。

方式二
我們知道最終的接收者實(shí)際上是通過tabbar的方法二的返回值決定的,所以我們只需要修改自定義tabbar的方法二的實(shí)現(xiàn)即可。

// 其中self.plusButton為中間凸起按鈕
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
     CGPoint newPoint = [self convertPoint:point toView:self.plusButton];
     //tabbar 是否隱藏,隱藏了就不需要考慮點(diǎn)擊了(tabbar 不展示的二級(jí)頁(yè)面需要處理,否則二級(jí)頁(yè)面將會(huì)觸發(fā) plusButton按鈕的點(diǎn)擊事件)
     if (self.hidden) {
           return [super hitTest:point withEvent:event];
        
     }else{
         // 判斷是否屬于按鈕范圍
         if ([self.plusButton pointInside:newPoint withEvent:event]) { 
               return self.plusButton;
         } else {
              return [super hitTest:point withEvent:event];
         }
      }
}

三、總結(jié)

在做類似這種UI時(shí),需要將自定義tabbar通過KVC替換掉原有tabbar,并重寫- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event返回合適的View去處理事件。

文章部分內(nèi)容借鑒鏈接:(http://www.itdecent.cn/p/dd39c49e7931)

文章持續(xù)更新中、希望對(duì)各位有所幫助、有問題可留言 大家共同學(xué)習(xí).

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

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

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