天天看點

[iOS]系統UITabBarController詳解及自定義(完)

對于UITabBarController, 大家都不陌生, 但是有時候又不那麼的熟悉, 下面就來再認識一下這個熟悉的陌生人.

以下使用微信的tabBar圖示;

一. 系統UITabBarController基本使用

1.1 基本用法

UITabBarController的使用, 其實很簡單, 這裡直接給出相應代碼:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    // 初始化UITabBarController執行個體對象
    UITabBarController *tabBar = [[UITabBarController alloc]init];
    // 建立子控制器
    UIViewController *vc1 = [[UIViewController alloc]init];
    vc1.view.backgroundColor = [UIColor redColor];
    // 設定标題
    vc1.tabBarItem.title = @"微信";
    // 設定選中狀态的圖檔
    vc1.tabBarItem.selectedImage = [UIImage imageNamed:@"tabbar_mainframeHL"];
    // 設定未選中狀态的圖檔
    vc1.tabBarItem.image = [UIImage imageNamed:@"tabbar_mainframe"] ;
    // 設定右上角顯示數字(例如: 未讀消息數目)
    vc1.tabBarItem.badgeValue = @"100";
    // 右上角數字背景色
    vc1.tabBarItem.badgeColor = [UIColor greenColor];

    UIViewController *vc2 = [[UIViewController alloc]init];
    vc2.view.backgroundColor = [UIColor orangeColor];
    vc2.tabBarItem.title = @"聯系人";
    vc2.tabBarItem.selectedImage = [UIImage imageNamed:@"tabbar_contactsHL"];
    vc2.tabBarItem.image = [UIImage imageNamed:@"tabbar_contacts"];

    UIViewController *vc3 = [[UIViewController alloc]init];
    vc3.view.backgroundColor = [UIColor cyanColor];
    vc3.tabBarItem.title = @"發現";
    vc3.tabBarItem.image = [UIImage imageNamed:@"tabbar_discover"];
    vc3.tabBarItem.selectedImage = [UIImage imageNamed:@"tabbar_discoverHL"];

    UIViewController *vc4 = [[UIViewController alloc]init];
    vc4.view.backgroundColor = [UIColor whiteColor];
    vc4.tabBarItem.title = @"我";
    vc4.tabBarItem.image = [UIImage imageNamed:@"tabbar_me"];
    vc4.tabBarItem.selectedImage = [UIImage imageNamed:@"tabbar_meHL"];


    // 添加子視圖到tabbar
    tabBar.viewControllers = @[vc1, vc2, vc3, vc4];

    // 設定為window跟視圖
    self.window.rootViewController = tabBar;
    return YES;
}
           

以上代碼直接寫在xxAppDelegate.m的上面這個方法裡即可;

效果如下:

[iOS]系統UITabBarController詳解及自定義(完)
注意:這裡使用的是微信的圖示, 是綠色的, 設定完後變成了藍色, 而且上面也沒有設定選中及未選中文字的顔色, 這裡都被預設設定了, 最主要的是沒有顯示我原先圖示的顔色.( 這樣美工是不同意的 ��).

1.2. 顯示原圖

根據上面的問題, 我們先來看看圖示的問題, 為了不被系統渲染成藍色, 這裡我們在設定各個控制器的選中和未選中的圖示的時候, 調用一下UIImage的這個方法即可imageWithRenderingMode:

// 設定選中狀态的圖檔
    vc1.tabBarItem.selectedImage = [[UIImage imageNamed:@"tabbar_mainframeHL"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    // 設定未選中狀态的圖檔
    vc1.tabBarItem.image = [[UIImage imageNamed:@"tabbar_mainframe"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
           
[iOS]系統UITabBarController詳解及自定義(完)

這樣就能正确顯示我們原先的圖檔了;

1.3 修改文字顔色

但是文字的顔色并不是我們需要的, 我們可以通過下面的方法, 來修改文字的顔色:

// 未選中狀态下文字顔色
 [vc1.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor redColor]} forState:UIControlStateNormal];
// 選中狀态下的文字顔色
 [vc1.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor blueColor]} forState:UIControlStateSelected];
           

這是設定選中和未選中狀态下的标題屬性, 效果如下:

[iOS]系統UITabBarController詳解及自定義(完)

這裡我隻是修改了前兩個控制器的文字, 後面的還是用的預設的.

上面是修改按鈕标題的文字屬性, 按鈕右上角的角标的文字屬性, 可使用下面的方法來修改:

// 未選中狀态下的角标文字顔色
[vc1.tabBarItem setBadgeTextAttributes:@{NSForegroundColorAttributeName: [UIColor blackColor]} forState:UIControlStateNormal];
// 選中狀态下的角标文字顔色
 [vc1.tabBarItem setBadgeTextAttributes:@{NSForegroundColorAttributeName: [UIColor orangeColor]} forState:UIControlStateSelected];
           
[iOS]系統UITabBarController詳解及自定義(完)
[iOS]系統UITabBarController詳解及自定義(完)

以上就是系統自帶UITabBarController及相關屬性的設定, 對于圖示規則的需求基本都能滿足, 如果還有其他的需求, 系統不能滿足的, 就隻能自定義了.

二. 自定義tabBarController

對于自定義的tabBar, 我們一般還是定義為UITabBarController的子類:

這樣我們可以借助UITabBarController的一些屬性和方法, 例如切換控制器; 不用再去寫切換的邏輯;

實際上, 我們說的自定義的tabBar, 對數情況下是自定義的底部的tabBar; 是以, 我們的重點是來設定底部視圖的實作.

我們自定義的時候, 一般有兩種選擇:

- 一種是, 隐藏掉系統的tabBar, 完全重新布局;

- 另一種是, 使用系統的tabBar, 但是自定義tabBarItem

不管是哪一種, 都需要自定義一個tabBarItem, 是以, 先來看看怎麼定義這個tabBarItem;

2.1 自定義item –LZTabBarItem
這個類, 主要做的是布局item, 及響應點選事件

我們定義一個類* LZTabBarItem*, 繼承自UIView, .h聲明檔案如下:

//
//  LZTabBarItem.h
//  LZTabBarController
//
//  Created by Artron_LQQ on 2016/12/12.
//  Copyright © 2016年 Artup. All rights reserved.
//

@protocol LZTabBarItemDelegate;
@interface LZTabBarItem : UIView

@property (nonatomic, copy) NSString *icon;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, strong) UIColor *titleColor;

@property (nonatomic, assign) id <LZTabBarItemDelegate> delegate;
@end

@protocol LZTabBarItemDelegate <NSObject>

- (void)tabBarItem:(LZTabBarItem *)item didSelectIndex:(NSInteger)index;
@end
           

這裡使用代理來回調點選事件; .m實作如下:

//
//  LZTabBarItem.m
//  LZTabBarController
//
//  Created by Artron_LQQ on 2016/12/12.
//  Copyright © 2016年 Artup. All rights reserved.
//

#import "LZTabBarItem.h"

static NSInteger defaultTag = ;
@interface LZTabBarItem ()

@property (nonatomic, strong)UIImageView *iconImageView;
@property (nonatomic, strong)UILabel *titleLabel;
@end

@implementation LZTabBarItem
- (instancetype)init {
    self = [super init];
    if (self) {

        self.userInteractionEnabled = YES;
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(itemClicked:)];
        [self addGestureRecognizer:tap];
    }

    return self;
}
// 重寫setTag方法
- (void)setTag:(NSInteger)tag {

    [super setTag:tag + defaultTag];
}

- (UIImageView *)iconImageView {
    if (_iconImageView == nil) {
        _iconImageView = [[UIImageView alloc]init];
        _iconImageView.contentMode = UIViewContentModeScaleAspectFit;
        [self addSubview:_iconImageView];
    }

    return _iconImageView;
}

- (UILabel *)titleLabel {
    if (_titleLabel == nil) {
        _titleLabel = [[UILabel alloc]init];
        _titleLabel.textAlignment = NSTextAlignmentCenter;
        _titleLabel.font = [UIFont systemFontOfSize:];
        _titleLabel.numberOfLines = ;
        _titleLabel.textColor = [UIColor grayColor];
        [self addSubview:_titleLabel];
    }

    return _titleLabel;
}

- (void)setIcon:(NSString *)icon {
    _icon = icon;

    self.iconImageView.image = [UIImage imageNamed:icon];
}

- (void)setTitle:(NSString *)title {
    _title = title;

    self.titleLabel.text = title;
}

- (void)setTitleColor:(UIColor *)titleColor {
    _titleColor = titleColor;

    self.titleLabel.textColor = titleColor;
}
- (void)layoutSubviews {
    [super layoutSubviews];

    CGFloat space = ;

    if (self.icon.length >  && self.title.length > ) {

        CGFloat iconHeight = (CGRectGetHeight(self.frame) - space * )*/ ;
        self.iconImageView.frame = CGRectMake(space, space, CGRectGetWidth(self.frame) -  * space, iconHeight);
        self.titleLabel.frame = CGRectMake(space, CGRectGetMaxY(self.iconImageView.frame) + space, CGRectGetWidth(self.frame) - *space, iconHeight/);
    } else if (self.icon.length > ) {

        self.iconImageView.frame = CGRectMake(, , CGRectGetWidth(self.frame) - , CGRectGetHeight(self.frame) - );
    } else if (self.title.length > ) {

        self.titleLabel.frame = CGRectMake(, CGRectGetHeight(self.frame) - , CGRectGetWidth(self.frame) - , );
    }
}

- (void)itemClicked:(UITapGestureRecognizer *)tap {

    if (self.delegate && [self.delegate respondsToSelector:@selector(tabBarItem:didSelectIndex:)]) {

        [self.delegate tabBarItem:self didSelectIndex:self.tag - defaultTag];
    }
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

@end
           

其實, 很簡單, 隻是添加了一個imageView, 一個label, 和一個單擊手勢來響應點選事件. 這裡我是在* layoutSubviews*方法裡來布局子視圖的, 這樣當視圖frame改變的時候, 其子視圖會做相應的調整;

這樣,tabBarItem的自定義就完成了,接下來就是自定義tabBar;

tabBar的定義, 有兩種方法:

- 一個是繼承自UIView, 完全自定義;

- 一個是繼承自UITabBar;

2.2 繼承自UIView

先來看一下繼承自UIView, 完全自定義的方法:

//
//  LZTabBar.h
//  LZTabBarController
//
//  Created by Artron_LQQ on 2016/12/12.
//  Copyright © 2016年 Artup. All rights reserved.
//

#import <UIKit/UIKit.h>

@class LZTabBarItem;
@protocol LZTabBarDelegate;
@interface LZTabBar : UIView

@property (nonatomic, strong)NSArray<LZTabBarItem *> *items;
@property (nonatomic, assign)id <LZTabBarDelegate> delegate;
@end

@protocol LZTabBarDelegate <NSObject>

- (void)tabBar:(LZTabBar *)tab didSelectItem:(LZTabBarItem *)item atIndex:(NSInteger)index ;
@end
           

這裡是.h檔案内容, 其屬性比較簡單, 隻設定了delegate和items;

.m的實作如下:

//
//  LZTabBar.m
//  LZTabBarController
//
//  Created by Artron_LQQ on 2016/12/12.
//  Copyright © 2016年 Artup. All rights reserved.
//

#import "LZTabBar.h"
#import "LZTabBarItem.h"

@interface LZTabBar ()<LZTabBarItemDelegate>

@property (nonatomic, strong) UIVisualEffectView *effectView;
@property (nonatomic, strong) UIView *topLine;
@end
@implementation LZTabBar

- (instancetype)init {
    self = [super init];
    if (self) {

        self.backgroundColor = [UIColor whiteColor];
    }

    return self;
}
- (UIView *)topLine {
    if (_topLine == nil) {
        _topLine = [[UIView alloc]init];
        _topLine.backgroundColor = [UIColor grayColor];
        [self addSubview:_topLine];
    }

    return _topLine;
}

- (UIVisualEffectView *)effectView {
    if (_effectView == nil) {

        UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
        _effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
        _effectView.alpha = ;
        [self addSubview:_effectView];
    }

    return _effectView;
}

- (void)layoutSubviews {
    [super layoutSubviews];


    self.effectView.frame = self.bounds;

    [self setupItems];

    self.topLine.frame = CGRectMake(, , CGRectGetWidth(self.frame), );
}

- (void)setupItems {

    CGFloat width = CGRectGetWidth(self.frame)/self.items.count;
    CGFloat height = CGRectGetHeight(self.frame);

    for (int i = ; i < self.items.count; i++) {

        LZTabBarItem *item = [self.items objectAtIndex:i];
        item.frame = CGRectMake(i*width, , width, height);
        [self addSubview:item];
        item.delegate = self;
    }
}

- (void)tabBarItem:(LZTabBarItem *)item didSelectIndex:(NSInteger)index {

    if (self.delegate && [self.delegate respondsToSelector:@selector(tabBar:didSelectItem:atIndex:)]) {

        [self.delegate tabBar:self didSelectItem:item atIndex:index];
    }
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

@end
           
這個類的主要作用是: 布局各個item, 在tabBar的位置, 及tabBar的一些内容.

接下來, 就是定義LZTabBarController了;

2.3 自定義LZTabBarController
這個類的主要作用是: 提供資料源, 繪制底部tabBar, 及關聯viewController;

在提供資料的時候, 我單獨設定了一個類類儲存這些資料, 而沒有直接設定為* LZTabBarController*的屬性:

#pragma mark - LZTabBarConfig
@interface LZTabBarConfig : NSObject

/**
 控制器數組, 必須設定
 */
@property (nonatomic, strong) NSArray *viewControllers;

/**
 item标題數組, 選擇設定
 */
@property (nonatomic, strong) NSArray *titles;

/**
 是否是導航, 預設 YES
 */
@property (nonatomic, assign) BOOL isNavigation;

/**
 選中狀态下的圖檔數組
 */
@property (nonatomic, strong) NSArray *selectedImages;

/**
 正常狀态下的圖檔數組
 */
@property (nonatomic, strong) NSArray *normalImages;

/**
 選中狀态下的标題顔色 預設: red
 */
@property (nonatomic, strong) UIColor *selectedColor;

/**
 正常狀态下的标題顔色 預設: gray
 */
@property (nonatomic, strong) UIColor *normalColor;
@end
           

提供資料源的時候, 隻需要配置這個config即可;

其.m檔案, 隻是設定了一些預設值:

@implementation LZTabBarConfig
- (instancetype)init {
    self = [super init];
    if (self) {

        _isNavigation = YES;
        _normalColor = [UIColor grayColor];
        _selectedColor = [UIColor redColor];
    }

    return self;
}
@end
           

下面, 回到* LZTabBarController*, 其.h的聲明, 就簡潔許多:

#import <UIKit/UIKit.h>

@class LZTabBarConfig;
typedef LZTabBarConfig*(^tabBarBlock)(LZTabBarConfig *config);
@interface LZTabBarController : UITabBarController

/**
 是否可用自動旋轉螢幕
 */
@property (nonatomic, assign) BOOL isAutoRotation;

/**
 建立tabBarController

 @param block 配置建立tabBarController所需的參數
 @return 傳回tabBarController執行個體對象
 */
+ (instancetype)createTabBarController:(tabBarBlock)block;

/**
 擷取目前的tabBarController執行個體, 執行個體建立後可通過此方法擷取目前執行個體

 @return 傳回tabBarController執行個體對象
 */
+ (instancetype)defaultTabBarController;

/**
 隐藏底部tabBar的方法

 @param isAnimation 是否需要動畫
 */
- (void)hiddenTabBarWithAnimation:(BOOL)isAnimation;

/**
 顯示底部tabBar的方法

 @param isAnimation 是否需要動畫
 */
- (void)showTabBarWithAnimation:(BOOL)isAnimation;
@end
           

隻是提供了建立的方法, 及擷取目前執行個體和隐藏/顯示底部tabBar的方法;

.m中的實作:

//
//  LZTabBarController.m
//  LZTabBarController
//
//  Created by Artron_LQQ on 2016/12/12.
//  Copyright © 2016年 Artup. All rights reserved.
//

#import "LZTabBarController.h"
#import "LZTabBar.h"

static CGFloat lzTabBarHeight = ;
@interface LZTabBarController ()<LZTabBarDelegate>

@property (nonatomic, strong) LZTabBar *customTabBar;
@property (nonatomic, strong) LZTabBarConfig *config;
@end

@implementation LZTabBarController
- (LZTabBar *)customTabBar {

    if (_customTabBar == nil) {
        _customTabBar = [[LZTabBar alloc]init];
        _customTabBar.delegate = self;
    }

    return _customTabBar;
}

+ (instancetype)createTabBarController:(tabBarBlock)block {
    static dispatch_once_t onceToken;
    static LZTabBarController *tabBar;
    dispatch_once(&onceToken, ^{

        tabBar = [[LZTabBarController alloc]initWithBlock:block];
    });

    return tabBar;
}

+ (instancetype)defaultTabBarController {

    return [LZTabBarController createTabBarController:nil];
}

- (void)hiddenTabBarWithAnimation:(BOOL)isAnimation {

    if (isAnimation) {

        [UIView animateWithDuration: animations:^{

            self.customTabBar.alpha = ;
        }];
    } else {

        self.customTabBar.alpha = ;
    }
}

- (void)showTabBarWithAnimation:(BOOL)isAnimation {

    if (isAnimation) {

        [UIView animateWithDuration: animations:^{

            self.customTabBar.alpha = ;
        }];
    } else {

        self.customTabBar.alpha = ;
    }
}

- (instancetype)initWithBlock:(tabBarBlock)block {

    self = [super init];
    if (self) {

        LZTabBarConfig *config = [[LZTabBarConfig alloc]init];

        NSAssert(block, @"Param in zhe function, can not be nil");
        if (block) {

            _config = block(config);
        }

        NSAssert(_config.viewControllers, @"Param 'viewControllers' in the 'config', can not be nil");
        [self setupViewControllers];
        [self setupTabBar];

        _isAutoRotation = YES;
    }

    return self;
}

- (void)setupViewControllers {

    if (_config.isNavigation) {

        NSMutableArray *vcs = [NSMutableArray arrayWithCapacity:_config.viewControllers.count];
        for (UIViewController *vc in _config.viewControllers) {
            if (![vc isKindOfClass:[UINavigationController class]]) {
                UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:vc];
                [vcs addObject:nav];
            } else {
                [vcs addObject:vc];
            }
        }

        self.viewControllers = [vcs copy];
    } else {

        self.viewControllers = [_config.viewControllers copy];
    }
}

- (void)setupTabBar {

    NSMutableArray *items = [NSMutableArray array];
    for (int i = ; i < _config.viewControllers.count; i++) {
        LZTabBarItem *item = [[LZTabBarItem alloc]init];

        if (i == ) {

            item.icon = _config.selectedImages[i];
            if (_config.titles.count > ) {
                item.titleColor = _config.selectedColor;
            }
        } else {

            item.icon = _config.normalImages[i];
            if (_config.titles.count > ) {

                item.titleColor = _config.normalColor;
            }

        }
        if (i < _config.titles.count) {

            item.title = _config.titles[i];
        }

        [items addObject:item];
        item.tag = i;
    }
    // 隐藏掉系統的tabBar
    self.tabBar.hidden = YES;
    self.customTabBar.items = [items copy];
    self.customTabBar.frame = CGRectMake(, CGRectGetHeight(self.view.frame) - lzTabBarHeight, CGRectGetWidth(self.view.frame), lzTabBarHeight);
    [self.view addSubview:self.customTabBar];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    self.view.backgroundColor = [UIColor whiteColor];
    self.selectedIndex = ;
}

#pragma mark - LZTabBarDelegate
- (void)tabBar:(LZTabBar *)tab didSelectItem:(LZTabBarItem *)item atIndex:(NSInteger)index {

    NSMutableArray *items = [NSMutableArray arrayWithCapacity:];
    for (UIView *view in tab.subviews) {
        if ([view isKindOfClass:[LZTabBarItem class]]) {

            [items addObject:view];
        }
    }

    for (int i = ; i < items.count; i++) {

        UIView *view = items[i];
        if ([view isKindOfClass:[LZTabBarItem class]]) {
            LZTabBarItem *item = (LZTabBarItem *)view;
            item.icon = self.config.normalImages[i];
            if (self.config.titles.count > ) {

                item.titleColor = _config.normalColor;
            }

        }
    }

    item.icon = self.config.selectedImages[index];

    if (self.config.titles.count > ) {

        item.titleColor = self.config.selectedColor;
    }

    self.selectedIndex = index;
}

// 螢幕旋轉時調整tabbar
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    self.customTabBar.frame = CGRectMake(, size.height - lzTabBarHeight, size.width, lzTabBarHeight);
}

- (BOOL)shouldAutorotate {

    return self.isAutoRotation;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    if (self.isAutoRotation) {

        return UIInterfaceOrientationMaskAllButUpsideDown;
    } else {

        return UIInterfaceOrientationMaskPortrait;
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
           

這裡主要的其實就是, * setupTabBar*方法

和* LZTabBarDelegate*的代理方法tabBar:(LZTabBar )tab didSelectItem:(LZTabBarItem )item atIndex:(NSInteger)index, 需要處理一些狀态的轉換;

到此, 第一種的自定義就結束了, 效果如下:

[iOS]系統UITabBarController詳解及自定義(完)

需要注意的是:

因為我們自定義了tabBar , 是以控制器的屬性hidesBottomBarWhenPushed 就失去效果了, 解決的方法可以是在合适的地方來調用隐藏/顯示的方法;

如果, 還想使用系統的* hidesBottomBarWhenPushed*效果, 可在使用的時候, 調整一下方法:一般, 我們是直接将tabBarController作為window的rootvc, 然後在其子控制器分别加上導航, 我們可以做如下調整:

将tabBar作為UINavigationController的rootvc, 然後把這個導航作為window的rootvc:

// 為了能夠使用hidesBottomBarWhenPushed, 不直接把tabBar設定為window的跟視圖, 而是設定為導航的rootvc, 然後把導航設定為window的跟視圖
    // 這樣, 在子控制器上就不用再添加導航了, 即設定: config.isNavigation = NO;
    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:tab];
// 打開hidesBottomBarWhenPushed
    nav.hidesBottomBarWhenPushed = YES;
    self.window.rootViewController = nav;
           

這樣做, 需要注意的是, 其子控制器就不用再添加導航了.

這樣, 就會有上面Gif的效果;

demo位址: LZTabBarController

2.4 繼承自UITabBar

繼承自UITabBar的方式, 與繼承自UIView, 主要的差別是LZTabBar的内容, 其他如LZTabBarItem 和LZTabBarController相關邏輯都是一樣的;

#import <UIKit/UIKit.h>

@class LZTabBarItem;
@protocol LZTabBarDelegate;
@interface LZTabBar : UITabBar

@property (nonatomic, strong)NSArray<LZTabBarItem *> *lzItems;
@property (nonatomic, assign)id <LZTabBarDelegate> lzDelegate;
@end

@protocol LZTabBarDelegate <NSObject>

- (void)tabBar:(LZTabBar *)tab didSelectItem:(LZTabBarItem *)item atIndex:(NSInteger)index ;

@end
           

.m的實作中, 主要是将系統的item移除掉, 然後添加上自定義的item:

#import "LZTabBar.h"

@interface LZTabBar ()<LZTabBarItemDelegate>

@end
@implementation LZTabBar

- (instancetype)init {
    self = [super init];
    if (self) {

        self.backgroundColor = [UIColor whiteColor];
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];

    // 移除系統的tabBarItem
    Class class = NSClassFromString(@"UITabBarButton");
    for (UIView *item in self.subviews) {
        if ([item isKindOfClass:class]) {
            [item removeFromSuperview];
        }
    }
    // 設定自定義的tabBarItem
    [self setupItems];
}

- (void)setupItems {

    CGFloat width = CGRectGetWidth(self.frame)/self.items.count;
    CGFloat height = CGRectGetHeight(self.frame);

    for (int i = ; i < self.lzItems.count; i++) {

        LZTabBarItem *item = [self.lzItems objectAtIndex:i];
        item.frame = CGRectMake(i*width, , width, height);
        [self addSubview:item];
        item.delegate = self;
    }
}

- (void)tabBarItem:(LZTabBarItem *)item didSelectIndex:(NSInteger)index {

    if (self.lzDelegate && [self.lzDelegate respondsToSelector:@selector(tabBar:didSelectItem:atIndex:)]) {

        [self.lzDelegate tabBar:self didSelectItem:item atIndex:index];
    }
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

@end
           

其最終的效果是一樣的, 隻不過我們可以在執行push操作的時候使用控制器的* hidesBottomBarWhenPushed*屬性來隐藏底部的tabBar;

(完)