美文网首页iOS之家
[iOS]系统及自定义UITabBarController

[iOS]系统及自定义UITabBarController

作者: 流火绯瞳 | 来源:发表于2016-12-13 18:16 被阅读838次

    对于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的上面这个方法里即可;
    效果如下:

    注意:这里使用的是微信的图标, 是绿色的, 设置完后变成了蓝色, 而且上面也没有设置选中及未选中文字的颜色, 这里都被默认设置了, 最主要的是没有显示我原先图标的颜色.( 这样美工是不同意的 😢).

    1.2. 显示原图

    根据上面的问题, 我们先来看看图标的问题, 为了不被系统渲染成蓝色, 这里我们在设置各个控制器的选中和未选中的图标的时候, 调用一下UIImage的这个方法即可imageWithRenderingMode:

    // 设置选中状态的图片
        vc1.tabBarItem.selectedImage = [[UIImage imageNamed:@"tabbar_mainframeHL"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
        // 设置未选中状态的图片
        vc1.tabBarItem.image = [[UIImage imageNamed:@"tabbar_mainframe"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    

    这样就能正确显示我们原先的图片了;

    1.3 修改文字颜色

    但是文字的颜色并不是我们需要的, 我们可以通过下面的方法, 来修改文字的颜色:

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

    这是设置选中和未选中状态下的标题属性, 效果如下:

    设置文字属性

    这里我只是修改了前两个控制器的文字, 后面的还是用的默认的.
    上面是修改按钮标题的文字属性, 按钮右上角的角标的文字属性, 可使用下面的方法来修改:

    // 未选中状态下的角标文字颜色
    [vc1.tabBarItem setBadgeTextAttributes:@{NSForegroundColorAttributeName: [UIColor blackColor]} forState:UIControlStateNormal];
    // 选中状态下的角标文字颜色
     [vc1.tabBarItem setBadgeTextAttributes:@{NSForegroundColorAttributeName: [UIColor orangeColor]} forState:UIControlStateSelected];
    
    角标文字未选中状态颜色: 黑色 角标文字选中状态颜色: 橘色

    以上就是系统自带UITabBarController及相关属性的设置, 对于图标规则的需求基本都能满足, 如果还有其他的需求, 系统不能满足的, 就只能自定义了.

    二. 自定义tabBarController

    对于自定义的tabBar, 我们一般还是定义为UITabBarController的子类:

    @interface LZTabBarController : 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 = 100000;
    @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:10];
            _titleLabel.numberOfLines = 0;
            _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 = 6.0;
        
        if (self.icon.length > 0 && self.title.length > 0) {
            
            CGFloat iconHeight = (CGRectGetHeight(self.frame) - space * 3)*2/3.0 ;
            self.iconImageView.frame = CGRectMake(space, space, CGRectGetWidth(self.frame) - 2 * space, iconHeight);
            self.titleLabel.frame = CGRectMake(space, CGRectGetMaxY(self.iconImageView.frame) + space, CGRectGetWidth(self.frame) - 2*space, iconHeight/2.0);
        } else if (self.icon.length > 0) {
            
            self.iconImageView.frame = CGRectMake(2, 2, CGRectGetWidth(self.frame) - 4, CGRectGetHeight(self.frame) - 4);
        } else if (self.title.length > 0) {
            
            self.titleLabel.frame = CGRectMake(2, CGRectGetHeight(self.frame) - 22, CGRectGetWidth(self.frame) - 4, 20);
        }
    }
    
    - (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文件内容, 其属性比较简单, 只设置了delegateitems;
    .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 = 1.0;
            [self addSubview:_effectView];
        }
        
        return _effectView;
    }
    
    - (void)layoutSubviews {
        [super layoutSubviews];
        
        
        self.effectView.frame = self.bounds;
        
        [self setupItems];
        
        self.topLine.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), 0.6);
    }
    
    - (void)setupItems {
        
        CGFloat width = CGRectGetWidth(self.frame)/self.items.count;
        CGFloat height = CGRectGetHeight(self.frame);
        
        for (int i = 0; i < self.items.count; i++) {
            
            LZTabBarItem *item = [self.items objectAtIndex:i];
            item.frame = CGRectMake(i*width, 0, 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 = 49.0;
    @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:0.2 animations:^{
                
                self.customTabBar.alpha = 0;
            }];
        } else {
            
            self.customTabBar.alpha = 0;
        }
    }
    
    - (void)showTabBarWithAnimation:(BOOL)isAnimation {
        
        if (isAnimation) {
            
            [UIView animateWithDuration:0.2 animations:^{
                
                self.customTabBar.alpha = 1.0;
            }];
        } else {
            
            self.customTabBar.alpha = 1.0;
        }
    }
    
    - (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 = 0; i < _config.viewControllers.count; i++) {
            LZTabBarItem *item = [[LZTabBarItem alloc]init];
            
            if (i == 0) {
                
                item.icon = _config.selectedImages[i];
                if (_config.titles.count > 0) {
                    item.titleColor = _config.selectedColor;
                }
            } else {
                
                item.icon = _config.normalImages[i];
                if (_config.titles.count > 0) {
                    
                    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(0, 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 = 0;
    }
    
    #pragma mark - LZTabBarDelegate
    - (void)tabBar:(LZTabBar *)tab didSelectItem:(LZTabBarItem *)item atIndex:(NSInteger)index {
        
        NSMutableArray *items = [NSMutableArray arrayWithCapacity:0];
        for (UIView *view in tab.subviews) {
            if ([view isKindOfClass:[LZTabBarItem class]]) {
                
                [items addObject:view];
            }
        }
        
        for (int i = 0; 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 > 0) {
                    
                    item.titleColor = _config.normalColor;
                }
                
            }
        }
        
        item.icon = self.config.selectedImages[index];
        
        if (self.config.titles.count > 0) {
            
            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(0, 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 , 需要处理一些状态的转换;
    到此, 第一种的自定义就结束了, 效果如下:

    需要注意的是:
    因为我们自定义了tabBar , 所以控制器的属性hidesBottomBarWhenPushed 就失去效果了, 解决的方法可以是在合适的地方来调用隐藏/显示的方法;
    如果, 还想使用系统的hidesBottomBarWhenPushed效果, 可在使用的时候, 调整一下方法:一般, 我们是直接将tabBarController作为windowrootvc, 然后在其子控制器分别加上导航, 我们可以做如下调整:
    tabBar作为UINavigationControllerrootvc, 然后把这个导航作为windowrootvc:

    // 为了能够使用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的内容, 其他如LZTabBarItemLZTabBarController相关逻辑都是一样的;

    #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 = 0; i < self.lzItems.count; i++) {
            
            LZTabBarItem *item = [self.lzItems objectAtIndex:i];
            item.frame = CGRectMake(i*width, 0, 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;

    demo地址

    (完)

    Github LQQZYY
    CSDN博客 流火绯瞳
    新浪微博 杯水_沧海
    QQ 302934443

    相关文章

      网友评论

        本文标题:[iOS]系统及自定义UITabBarController

        本文链接:https://www.haomeiwen.com/subject/xtkbmttx.html