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

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

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;

(完)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS自定义 TabBar 主要分为以下几个步骤: 1. 创建自定义 TabBar 创建一个继承于 UITabBar 的类,重写初始化方法和 layoutSubviews 方法,实现自定义 TabBar 的样式和布局。 2. 实现自定义 TabBarItem 创建一个继承于 UIButton 的类,用于实现自定义TabBarItem 样式,例如添加图片、文字等。 3. 设置自定义 TabBarItem 在自定义 TabBar 的初始化方法中,添加自定义TabBarItem,将其添加到 TabBar 上。 4. 替换系统 TabBar 在 AppDelegate 中,找到 TabBarControllertabBar 属性,将其替换为自定义TabBar。 示例代码: 自定义 TabBar 类: ``` class CustomTabBar: UITabBar { var items: [CustomTabBarItem] = [] override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setup() { // 隐藏默认的 TabBar self.tintColor = .clear self.backgroundImage = UIImage() self.shadowImage = UIImage() self.backgroundColor = .white } override func layoutSubviews() { super.layoutSubviews() // 设置自定义 TabBarItem 的布局 let itemWidth = self.frame.size.width / CGFloat(items.count) var itemIndex: CGFloat = 0 for item in items { item.frame = CGRect(x: itemWidth * itemIndex, y: 0, width: itemWidth, height: self.frame.size.height) itemIndex += 1 } } } ``` 自定义 TabBarItem 类: ``` class CustomTabBarItem: UIButton { var title: String? var normalImage: UIImage? var selectedImage: UIImage? override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setup() { // 设置 TabBarItem 的样式 self.imageView?.contentMode = .scaleAspectFit self.titleLabel?.font = UIFont.systemFont(ofSize: 12) self.setTitleColor(.gray, for: .normal) self.setTitleColor(.black, for: .selected) } override func layoutSubviews() { super.layoutSubviews() // 设置 TabBarItem 的布局 let imageHeight = self.frame.size.height * 0.6 self.imageView?.frame = CGRect(x: (self.frame.size.width - imageHeight) / 2, y: 5, width: imageHeight, height: imageHeight) self.titleLabel?.frame = CGRect(x: 0, y: self.frame.size.height - 20, width: self.frame.size.width, height: 20) } func set(title: String?, normalImage: UIImage?, selectedImage: UIImage?) { self.title = title self.normalImage = normalImage self.selectedImage = selectedImage // 设置 TabBarItem 的标题和图片 self.setTitle(title, for: .normal) self.setImage(normalImage, for: .normal) self.setImage(selectedImage, for: .selected) } } ``` 在自定义 TabBar 的初始化方法中,添加自定义TabBarItem: ``` class CustomTabBar: UITabBar { var items: [CustomTabBarItem] = [] override init(frame: CGRect) { super.init(frame: frame) setup() // 添加 TabBarItem let item1 = CustomTabBarItem() item1.set(title: "首页", normalImage: UIImage(named: "home_normal"), selectedImage: UIImage(named: "home_selected")) self.addSubview(item1) items.append(item1) let item2 = CustomTabBarItem() item2.set(title: "消息", normalImage: UIImage(named: "message_normal"), selectedImage: UIImage(named: "message_selected")) self.addSubview(item2) items.append(item2) let item3 = CustomTabBarItem() item3.set(title: "我的", normalImage: UIImage(named: "mine_normal"), selectedImage: UIImage(named: "mine_selected")) self.addSubview(item3) items.append(item3) } // ... } ``` 在 AppDelegate 中,找到 TabBarControllertabBar 属性,将其替换为自定义TabBar: ``` func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // ... let tabBarController = UITabBarController() tabBarController.viewControllers = [viewController1, viewController2, viewController3] // 替换为自定义 TabBar let customTabBar = CustomTabBar(frame: tabBarController.tabBar.frame) tabBarController.setValue(customTabBar, forKey: "tabBar") // ... return true } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值