博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS之自定义tabBar
阅读量:7039 次
发布时间:2019-06-28

本文共 14629 字,大约阅读时间需要 48 分钟。

在iOS原生的tabBar中,能够实现按钮的点击事件,能够实现视图控制器的切换等,但是在实际工程中,对于tabBar的要求的功能往往是系统自己实现不了的,所以我们这里就需要用到自定义的tabBar了。 对于tabBar上展示视图控制器,我们会采用的是在把几个视图控制直接加载到tabBarController上去。这里新建三个视图控制器,由于在 一、系统样式 ViewController会有其他代码,所以我们这里另一写一个类,在这里只设置一个背景颜色就可以了。所以我们先新建一个类叫做WJViewController,让它继承自UIViewController。这里设置视图的背景颜色,这里可以设置为随机色。

// 设置背景颜色为随机色    self.view.backgroundColor = [UIColor colorWithRed:arc4random() % 256 /255.0 green:arc4random() % 256 /255.0 blue:arc4random() % 256 /255.0 alpha:1.0];复制代码

然后新建三个视图控制器,继承自WJViewController,这样三个视图控制的背景颜色都有了。新建的三个类,分别命名为WJFirstViewController、WJSecondViewController、WJThirdViewController。然后我们去实现相关方法。 1.首先创建一个tabBarController,用于接收实例化好的视图控制器。 // 1.创建标签栏控制器 UITabBarController *tabBarController = [[UITabBarController alloc]init]; 2.然后就可创建需要让标签栏控制器管理的子视图控制器:

// 1>.第一个视图控制器    WJFirstViewController *first = [[WJFirstViewController alloc]init];    first.tabBarItem.title = @"first";    first.tabBarItem.image = [[UIImage imageNamed:@"tiaoman_u.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];    first.tabBarItem.selectedImage = [[UIImage imageNamed:@"tiaoman_d.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];复制代码
// 2>.第二个视图控制器    WJSecondViewController *second = [[WJSecondViewController alloc]init];    second.tabBarItem.title = @"second";    second.tabBarItem.image = [[UIImage imageNamed:@"faxian_u.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];    second.tabBarItem.selectedImage = [[UIImage imageNamed:@"faxian_d.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];复制代码
// 3>.第三个视图控制器    WJThirdViewController *third = [[WJThirdViewController alloc]init];    third.tabBarItem.title = @"third";    third.tabBarItem.image = [[UIImage imageNamed:@"wode_u.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];    third.tabBarItem.selectedImage = [[UIImage imageNamed:@"wode_d.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];复制代码

3.对子视图控制器进行管理 有两种方案可以选择:一是用数组进行接收,二是用一个方法进行接收子视图控制器。 法一: //tabBarController.viewControllers = @[first, second, third]; 法二:

[tabBarController addChildViewController:first];    [tabBarController addChildViewController:second];    [tabBarController addChildViewController:third];复制代码

这里最好使用第二种方法进行对子视图控制器进行管理。 代码进行到这里就可以把视图控制器tabBarController展示在Windows上了,所以需要把tabBarController设为根视图。

// 可以通过每个已经显示在界面上的视图,拿到当前应用程序的window    self.view.window.rootViewController = tabBarController;}复制代码

这样代码进行到这里系统样式的功能就已经实现了,但是对于我们实际要求的功能相差甚远,所以我们开始自定义的tabBar的创建。 二、自定义样式 下面我们来简单分析下系统的tabBar的功能。 2.1分析 分析首先按钮有按钮点击事件,点击按钮后会改变相应的视图控制器,而且点击按钮后的图标会有相应的改变。而自定义的tabBar也需要达到这些功能,甚至还需要达到自定义按钮的形状的和功能的要求。 对于系统的tabBar来说,能够展示按钮的文字和图片,而这些内容是加载在tabBar的_UITabBarBackgroundView上的UITabBarButton上的UILabel和UIImageView上的。而我们要自定义按钮就需要覆盖系统本身的控件,但这些控件我们是拿不到的,用点语法这些控件是不能联想出来的,但我们又要实现和系统一样的功能,我们只能用一个方法把tabBar上的所有控件移除,因此要用遍历的方法实现移除;我们移除了系统自带的tabBar后就需要自定义一个wjTabBar来代替原有的tabBar。然后在wjTabBar上添加按钮,然后设置相应的点击事件,更改相应的状态就可实现和系统一样的功能。

// 声明一个wjTabBar的全局变量@property (nonatomic, strong) WJTabBar *wj_tabBar;复制代码
- (void)viewDidAppear:(BOOL)animated {    [super viewDidAppear:animated];        // 2.删除自动创建的tabBarButton    for (UIView *view in self.tabBar.subviews) {        // 打印tabBar上所有控件        NSLog(@"%@",self.tabBar.subviews);        // 移除tabBar上所有的子控件        [view removeFromSuperview];    }    // 把self.wj_tabBar添加到视图上    [self.tabBar addSubview:self.wj_tabBar];}复制代码

对wj_tabBar设置懒加载

#pragma mark - 懒加载- (WJTabBar *)wj_tabBar {    if (!_wj_tabBar) {        // 创建wj_tabBar        _wj_tabBar = [[WJTabBar alloc]init];        // 设置frame        _wj_tabBar.frame = self.tabBar.bounds;        // 设置一个背景颜色        _wj_tabBar.backgroundColor = [UIColor cyanColor];    }    return _wj_tabBar;}复制代码

2.2现在分析下按钮的创建: 按钮的创建应该视图控制器创建有关,所以在设计方法的时候应该传一个视图控制器的参数;按钮还应该设置文字,选中时的图片和普通状态下的图片。 2.2.1把tabBar展示到视图上 考虑到后期调用的方便,可以在.h文件中暴露出接口,以供使用;所以在.h文件中设置方法,然后在.m文件实现相关的方法。

#pragma mark - 添加子视图控制器- (void)addController:(UIViewController *)controller withTitle:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName {    // 设置tabBarItem的子视图    controller.tabBarItem.title = title;    controller.tabBarItem.image = [[UIImage imageNamed:imageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];    controller.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];        // 将视图控制器添加到标签栏控制器中    [self addChildViewController:controller];        // 可以让自己定制的tabBar去创建一个对应的按钮    [self.wj_tabBar addButtonWithTabBarItem:controller.tabBarItem];        /* 测试的    static int i = 0;    if (i == 0) {        WJTabBarButton *button = [[WJTabBarButton alloc]initWithFrame:CGRectMake(10, 0, 45, 45)];        button.item = controller.tabBarItem;                button.normalColor = [UIColor blueColor];        button.selectedColor = [UIColor greenColor];        [button addTarget:self action:@selector(firstClick:)];        [self.wj_tabBar addSubview:button];        i = 1;    }     */}复制代码

然后去ViewControllers去添加视图控制器到tabBar上

#pragma mark - 创建视图控制器- (void)wj_creatControll {    // 1.创建标签栏控制器    WJTabBarController *tabBarController = [[WJTabBarController alloc]init];        WJFirstViewController *first = [[WJFirstViewController alloc]init];    [tabBarController addController:first withTitle:@"first" imageName:@"tiaoman_u.png" selectedImageName:@"tiaoman_d.png"];        WJSecondViewController *second = [[WJSecondViewController alloc]init];    [tabBarController addController:second withTitle:@"second" imageName:@"faxian_u.png" selectedImageName:@"faxian_d.png"];        //WJThirdViewController *third = [[WJThirdViewController alloc]init];    //[tabBarController addController:third withTitle:@"third" imageName:@"wode_u.png" selectedImageName:@"wode_d.png"];        // 可以通过每个已经显示在界面上的视图,拿到当前应用程序的window    self.view.window.rootViewController = tabBarController;        // 设置第几个被选中    tabBarController.selectedIndex = 0;        // 这只centerView    UIButton *center = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 60, 60)];    [center setImage:[UIImage imageNamed:@"luffy1@2x.png"] forState:UIControlStateNormal];    tabBarController.centerView = center;}复制代码

以上涉及到了WJTabBarButton这个类,这个类直接继承自UIView,在这个类中定义了几个属性:

2.2.2创建按钮 我们这里就可以去创建按钮了,首先去创建出按钮,然后去设计frame。 自定义的tabBar,我们就可以实现系统实现不了的样式,比如中间的按钮样式特别定制,比如像微博的tabBar中间的‘+’按钮。我们下面就实现实现下有特殊按钮的样式的tabBar。

#pragma mark - 当考虑有centerView的时候- (void)setFrameWithCenter {    // 通用属性    CGFloat tabBarWidth = self.frame.size.width;    CGFloat tabBarHeight = self.frame.size.height;    NSInteger buttonCount = self.subviews.count;    if (self.centerView) {        // 有centerView的情况        buttonCount -= 1;    }        // centerView的相关属性    CGFloat centerWidth = self.centerView.frame.size.width;    CGFloat centerHeight = self.centerView.frame.size.height;    CGFloat centerX = (tabBarWidth - centerWidth) / 2.0f;    CGFloat centerY;    if (centerHeight <= tabBarHeight) {        centerY = (tabBarHeight - centerHeight) / 2.0f;    }    else {        centerY = tabBarHeight - centerHeight;    }    self.centerView.frame = CGRectMake(centerX, centerY, centerWidth, centerHeight);        // 按钮frame    CGFloat buttonY = 0;    CGFloat buttonHeight = self.frame.size.height;    CGFloat buttonWidth = (tabBarWidth - centerWidth) / buttonCount;    CGFloat buttonX;    int i = 0;    for (UIView *wjview in self.subviews) {        // 拿到按钮        if (wjview.tag != CenterTag) {            WJTabBarButton *button = (WJTabBarButton *)wjview;            // 计算frame            // 中间按钮之前的button            if (i < buttonCount / 2) {                buttonX = i * buttonWidth;            }            else {                // 中间按钮之后的button                buttonX = i * buttonWidth + centerWidth;            }                        // 设置frame            button.frame = CGRectMake(buttonX, buttonY, buttonWidth, buttonHeight);            // 设置默认选中的按钮            if (i == self.selectedIndex) {                button.isSelected = YES;            }            // 设置tag值            button.tag = ButtonTag + i;            ++i;        }    }}复制代码

下面给centerView进行赋值

#pragma mark - centerView赋值-(void)setCenterView:(UIView *)centerView {        _centerView = centerView;       UIView *view = (UIView *)[self viewWithTag:CenterTag];    if (view) {        // 移除之前的tag        [view removeFromSuperview];    }    else {        _centerView.tag = CenterTag;        // 显示在界面上        [self addSubview:_centerView];    }}复制代码

但在外边调用的时候需要传一个中间按钮的方法,把中间按钮的一些属性传给上面的代码即:

#pragma mark - 外部给centerView赋值-(void)setCenterView:(UIView *)centerView {        _centerView = centerView;    // 在tabBar上显示中间的视图    self.wj_tabBar.centerView = centerView;}复制代码

最后在layoutSubView中实现以上的方法。

2.2.3创建按钮上的文字和图片

// 其实就是一个模型@property (nonatomic, strong) UITabBarItem *item;// ==================属性===============// 按钮是否选中@property (nonatomic, assign) BOOL isSelected;// 按钮选中颜色@property (nonatomic, strong) UIColor *selectedColor;// 按钮普通状态颜色@property (nonatomic, strong) UIColor *normalColor;// 添加事件- (void)addTarget:(id)target action:(SEL)action;复制代码

在.m文件中实现相关方法;

首先对一些属性设置默认值,这里可以提供两个初始化的方法,以便以后可以用frame的方法进行初始化和直接init方法进行初始化。

- (instancetype)initWithFrame:(CGRect)frame {    if (self = [super initWithFrame:frame]) {                // 设置属性默认值        // 选中状态的颜色        self.selectedColor = [UIColor redColor];        // 普通状态的颜色        self.normalColor = [UIColor lightGrayColor];    }    return self;}复制代码
- (instancetype)init {    if (self = [super init]) {        // 设置属性默认值        self.selectedColor = [UIColor redColor];        self.normalColor = [UIColor lightGrayColor];    }    return self;}复制代码

然后在按钮上去创建界面, 去创建子视图,这里只是单纯的创建子视图,而不去创建子视图的frame属性。这里去重写setter方法;

- (void)setItem:(UITabBarItem *)item {        _item = item;        // 移除按钮上原来的子视图    for (UIView *view in self.subviews) {        [view removeFromSuperview];    }    // 创建对应的子视图    // 1.图片    if (item.image || item.selectedImage) {        _imageView = [[UIImageView alloc]init];        [self addSubview:_imageView];        _imageView.image = item.image;        // 不缩放        [_imageView setContentMode:UIViewContentModeCenter];    }        // 2.文字    if (item.title) {        _textLabel = [[UILabel alloc] init];        [self addSubview:_textLabel];        _textLabel.text = item.title;        _textLabel.textAlignment = NSTextAlignmentCenter;        _textLabel.font = [UIFont systemFontOfSize:12.0];    }}复制代码

下一步就去设置子视图的frame属性,让其在视图即将创建的时候去设置frame属性,因为在这个时候,tabBar上的按钮的个数已经全部创建完成,所以使用layoutSubviews方法设置frame属性,这里我们先封装一个方法去设置子视图的frame。在计算视图的frame的时候最好用相对位置,最好不要把位置写死了,万一以后要调整的话,一个参数更改,其他的参数位置也会跟着变化。

// 计算frame- (void)setSubViewFrame {        // 通用    CGFloat buttonW = self.frame.size.width;    CGFloat buttonH = self.frame.size.height;        // 1.计算图片的frame    // 有图片    if (_imageView) {        CGFloat imageX = 0;        CGFloat imageY = 0;        CGFloat imageW = buttonW;        CGFloat imageH;        if (_textLabel) {            // 有文字            imageH = buttonH * 4 / 5.0f;        }        else {            // 没有文字            imageH = buttonH;        }        _imageView.frame = CGRectMake(imageX, imageY, imageW, imageH);    }        // 2.计算文字的frame    if (_textLabel) {        CGFloat textX = 0;        CGFloat textW = buttonW;        CGFloat textY;        CGFloat textH;        if (_imageView) {            // 有图片            textY = buttonH * 4 / 5.0f;            textH = buttonH / 5.0f;        }        else {            // 没有图片            textY = 0;            textH = buttonH;        }        _textLabel.frame = CGRectMake(textX, textY, textW, textH);    }}复制代码

然后把以上的方法在layoutSubviews中去实现下就可以了。 这里可以设置最终文字所要展示的文字颜色:

// 设置最终所需属性    _textLabel.textColor = self.normalColor;复制代码

2.3添加按钮的点击事件:

#pragma mark - 按钮的点击事件- (void)addTarget:(id)target action:(SEL)action {    _target = target;    _action = action;}复制代码
#pragma mark - 添加事件- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {   /*   // 在这里可以先测试下按钮的点击效果    if (self.isSelected) {                self.isSelected = NO;    }    else {                self.isSelected = YES;    }    */        // 响应点击事件    if ([_target respondsToSelector:_action]) {        [_target performSelector:_action withObject:self];    }}复制代码

按钮被点击后有选中的状态,之前的按钮就会失去被选中的状态,所以下面就去设置按钮的状态。 2.3.1按钮点击后改变选中状态

#pragma mark - 按钮点击- (void)buttonOnClick:(WJTabBarButton *)button {       // 把其他的按钮变成非选中状态    // 获取到原来的按钮    WJTabBarButton *wjButton = (WJTabBarButton *)[self viewWithTag:self.selectedIndex + ButtonTag];    wjButton.isSelected = NO;    wjButton.userInteractionEnabled = YES;        // 把当前点击的按钮变成选中状态    button.isSelected = YES;    self.selectedIndex = button.tag - ButtonTag;    button.userInteractionEnabled = NO;}复制代码

2.3.2按钮改变后更改颜色状态和文字

#pragma mark - 改变状态- (void)setIsSelected:(BOOL)isSelected {        _isSelected = isSelected;        if (isSelected) {        // 被选中的时候,更改选中按钮的图片和选中时候颜色        self.imageView.image = self.item.selectedImage;        self.textLabel.textColor = self.selectedColor;    }    else {         // 失去选中的时候,按钮变成普通状态,颜色变成普通状态的颜色        self.imageView.image = self.item.image;        self.textLabel.textColor = self.normalColor;    }}复制代码

2.4按钮点击后的视图控制器需要切换 分析:点击按钮视图切换,实质上是WJTabBar想要去切换视图控制器,但是他自己做不到,需要他人去帮他去做,这就要WJTabBarController去帮他实现视图的切换。我们可以用代理去实现点击按钮实现视图的切换。 那要实现代理,实在什么地方呢?答案是在选中的下标的set方法去实现,所以我们这里需要对选中下标的setter方法进行重写。

2.4.1对代理进行简单的分析: 代理的三要素:协议、代理、委托。这里的协议就是要切换到指定的视图控制器;代理就是WJTabBarController;委托就是WJTbaBar。 (1)代理方 首先在代理的.h文件去声明指定的协议

// 指定协议@protocol WJTabBarDelegate 
复制代码

然后需要一个代理,这相当于是对代理名的重写

// 需要一个代理@property (nonatomic, weak) id
delegate;复制代码

最后在.m文件调用代理的方法

#pragma mark - 重写set方法,改变选中下标,调用代理方法- (void)setSelectedIndex:(NSInteger)selectedIndex {    _selectedIndex = selectedIndex;        // 调用代理的方法    [self.delegate changeControllerWithIndex:self.selectedIndex];}复制代码

(2)委托方 首先要准守协议方法

// 遵守协议方法@interface WJTabBarController ()
复制代码

然后去设置代理人,这个代理人应该是在tabBar被加载的时候就应该设置的,所以应该在wj_tabBar的懒加载中加上代理人的设置

#pragma mark - 懒加载- (WJTabBar *)wj_tabBar {    if (!_wj_tabBar) {        _wj_tabBar = [[WJTabBar alloc]init];        _wj_tabBar.frame = self.tabBar.bounds;        _wj_tabBar.backgroundColor = [UIColor cyanColor];              // 设置代理人        _wj_tabBar.delegate = self;            }    return _wj_tabBar;}复制代码

最后要实现代理方法,(这是委托人需要执行的)

#pragma mark - 实现协议方法(切换视图控制器)- (void)changeControllerWithIndex:(NSInteger)index {    // 切换视图控制器    self.selectedIndex = index;}复制代码

以上就是自定义按钮的大概实现步骤。

三:总结 要实现自定义的按钮,就是需要覆盖系统原生的按钮,然后移除tabBar上的所有子控件,然后在tabBar上去创建一个自定义的tabBar,然后在tabBar上创建按钮,在按钮上去创建图片和文字;如果要添加中间的那种特殊定制的按钮,只需要把frame值设置好就应该可以了。实现页面的切换的话,就需要用到代理,让tabBarController去实现tabBar想实现的功能就可以了。


后面还有一篇较为简单的方法定义tabBar的: https://juejin.im/post/5a3143995188253da72e735f

转载地址:http://mgyal.baihongyu.com/

你可能感兴趣的文章
mac 版本号控制工具SmartSVN7.5.4(破解版)
查看>>
[Ubuntu] 如何设置静态 IP 和 DNS
查看>>
递归、非递归 反转单链表
查看>>
java的System.getProperty()方法能够获取的值
查看>>
内层元素设置position:relative后父元素overflow:hidden overflow:scroll失效 解决方法
查看>>
020 <one-to-one>、<many-to-one>单端关联上的lazy(懒加载)属性
查看>>
.Net中的7Zip——Sharpcompress
查看>>
Android_PendingIntent的使用
查看>>
VS2010 C++环境下DLL和LIB文件目录及名称修改
查看>>
【iOS XMPP】使用XMPPFramewok(三):好友状态
查看>>
linux 信号处理 四
查看>>
Linux 查看支持的语言,日期,时间,计算器
查看>>
javaWeb学习总结(10)- Filter(过滤器)学习
查看>>
在Linq to sql 和 Entity framework 中使用lambda表达式实现left join
查看>>
ENC28J60
查看>>
Web service是什么?
查看>>
php 简单连接数据库的操作
查看>>
10天学安卓-第六天
查看>>
使用XtraGrid自定义列计算1 z
查看>>
ORA-32004: obsolete or deprecated parameter(s) specified for RDBMS instance
查看>>