• 自定义TabBarController


    一、自定义的思路

    iOS中的TabBarController确实已经很强大了,大部分主流iOS应用都会采用。但是往往也不能满足全部的需求,因此需要自定义TabBar,自定义需要对系统的TabBar工作方式有很好的理解,自定义需要勇气。

    自定义TabBar的原则:尽量利用系统自带TabBar,只改需要改的地方。


    二、自定义TabBar的总体过程
    1.先把自带的TabBar条给取消了
    2.自己做一个view,上面放几个按钮,设定按钮的点击事件.并设置selectIndex。
    3.关联各个子viewController,覆盖相关事件。

    三、细节很重要

    1. 让自己创建的按钮关联到viewController:
    tabbarselectedIndex属性.设置这个属性就行了.
    2. 取消系统的高亮:
    可以自定义一个按钮.重写里面的setHighhighted方法,什么也不做就行了.(如果调用super就相当于没写)
    3. 关于几个按钮只选中一个的方法:
    设置一个属性,记录上一个选中的按钮.
    点击当前按钮时,把上一个按钮设置为未选中,并把当前按钮设置为选中,最后把当前按钮赋值给上一个按钮.

    四、初步自定义
    直接上代码,详见注释。
    XNTabBarController.h

    [objc] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #import <UIKit/UIKit.h>  
    2.   
    3. @interface XNTabBarController : UITabBarController  
    4.   
    5. @end  

    XNTabBarController.m

    [objc] view plaincopy在CODE上查看代码片派生到我的代码片
    1. //  
    2. //  XNTabBarController.m  
    3. //  
    4. //  
    5. //  Created by neng on 14-6-19.  
    6. //  Copyright (c) 2014年 neng. All rights reserved.  
    7. //  
    8.   
    9. #import "XNTabBarController.h"  
    10. #import "Common.h"  
    11. #import "XNTabBarButton.h"  
    12.   
    13. @interface XNTabBarController ()  
    14. /** 
    15.  *  设置之前选中的按钮 
    16.  */  
    17. @property (nonatomic, weak) UIButton *selectedBtn;  
    18. @end  
    19.   
    20. @implementation XNTabBarController  
    21.   
    22. - (void)viewDidLoad {  
    23.     [super viewDidLoad];  
    24.     //下面两个方法在开发中是经常会用到的  
    25. //    NSLog(@"%s",__func__);  
    26. //    NSLog(@"%@",self.view.subviews); //能打印出所有子视图,和其frame  
    27.     LogFun;  
    28.     LogSubviews(self.view);  
    29.   
    30.   
    31.     //删除现有的tabBar  
    32.     CGRect rect = self.tabBar.frame;  
    33.     [self.tabBar removeFromSuperview];  //移除TabBarController自带的下部的条  
    34.   
    35.     //测试添加自己的视图  
    36.     UIView *myView = [[UIView alloc] init];  
    37.     myView.frame = rect;  
    38.     myView.backgroundColor = [UIColor redColor];  
    39.     [self.view addSubview:myView];  
    40.   
    41.     for (int i = 0; i < 5; i++) {  
    42.         //UIButton *btn = [[UIButton alloc] init];  
    43.         XNTabBarButton *btn = [[XNTabBarButton alloc] init];  
    44.           
    45.         NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];  
    46.         NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];  
    47.   
    48.         [btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];  
    49.         [btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];  
    50.   
    51.         CGFloat x = i * myView.frame.size.width / 5;  
    52.         btn.frame = CGRectMake(x, 0, myView.frame.size.width / 5, myView.frame.size.height);  
    53.   
    54.         [myView addSubview:btn];  
    55.           
    56.         btn.tag = i;//设置按钮的标记, 方便来索引当前的按钮,并跳转到相应的视图  
    57.   
    58.         //带参数的监听方法记得加"冒号"  
    59.         [btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];  
    60.   
    61.         //设置刚进入时,第一个按钮为选中状态  
    62.         if (0 == i) {  
    63.             btn.selected = YES;  
    64.             self.selectedBtn = btn;  //设置该按钮为选中的按钮  
    65.         }  
    66.     }  
    67. }  
    68.   
    69. /** 
    70.  *  自定义TabBar的按钮点击事件 
    71.  */  
    72. - (void)clickBtn:(UIButton *)button {  
    73.     //1.先将之前选中的按钮设置为未选中  
    74.     self.selectedBtn.selected = NO;  
    75.     //2.再将当前按钮设置为选中  
    76.     button.selected = YES;  
    77.     //3.最后把当前按钮赋值为之前选中的按钮  
    78.     self.selectedBtn = button;  
    79.       
    80.     //4.跳转到相应的视图控制器. (通过selectIndex参数来设置选中了那个控制器)  
    81.     self.selectedIndex = button.tag;  
    82. }  
    83.   
    84. @end  

    XNTabBarButton.h

    [objc] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #import <UIKit/UIKit.h>  
    2.   
    3. @interface XNTabBarButton : UIButton  
    4.   
    5. @end  

    XNTabBarButton.m

    [objc] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #import "XNTabBarButton.h"  
    2.   
    3. @implementation XNTabBarButton  
    4. /**什么也不做就可以取消系统按钮的高亮状态*/  
    5. - (void)setHighlighted:(BOOL)highlighted{  
    6. //    [super setHighlighted:highlighted];  
    7. }  
    8.   
    9. @end  

    五、代码重构

    重构的目的是把代码放到他最该到的地方去. 提高可读写与可拓展性。

    对控件的重构要保证可重用性. 做到封装做其他应用时,可以直接拿过去用的地步.

    tips :
    1、关于initinitWithFrame:
    在对象初始化调用init,会调用initWithFrame方法.
    InitinitWithFrame都会被调用.
    建议自定义控件不要重init方法,需要初始化重写initWithFrame方法.
    好处:其他人调用无论是调用init,还是调用initWithFrame都会调用initWithFrame方法.

    2、关于控件的布局代码:
    建议写在layoutSubviews方法中.
    不要忘记写super方法
    将设置x,y,frame等写在这里面.
    3、自定义的Tabbar添加为系统TabBar的子视图,这样TabBar的切换自动隐藏/滑动功能就不用自己做了. (hidebottombaronpush)

    重构后的代码如下
    将自定义的TabBar单独建立,并将代码移过去。
    设置代理方法,工具栏按钮被选中,记录从哪里跳转到哪里. 

    XNTabBar.h

    [objc] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #import <UIKit/UIKit.h>  
    2. @class XNTabBar;  
    3.   
    4. @protocol XNTabBarDelegate <NSObject>  
    5. /** 
    6.  *  工具栏按钮被选中, 记录从哪里跳转到哪里. (方便以后做相应特效) 
    7.  */  
    8. - (void) tabBar:(XNTabBar *)tabBar selectedFrom:(NSInteger) from to:(NSInteger)to;  
    9.   
    10. @end  
    11.   
    12. @interface XNTabBar : UIView  
    13. @property(nonatomic,weak) id<XNTabBarDelegate> delegate;  
    14. /** 
    15.  *  使用特定图片来创建按钮, 这样做的好处就是可扩展性. 拿到别的项目里面去也能换图片直接用 
    16.  * 
    17.  *  @param image         普通状态下的图片 
    18.  *  @param selectedImage 选中状态下的图片 
    19.  */  
    20. -(void)addButtonWithImage:(UIImage *)image selectedImage:(UIImage *) selectedImage;  
    21. @end  


    XNTabBar.m


    [objc] view plaincopy在CODE上查看代码片派生到我的代码片
    1. //  
    2. //  XNTabBar.m  
    3. //  
    4. //  Created by neng on 14-6-19.  
    5. //  Copyright (c) 2014年 neng. All rights reserved.  
    6. //  
    7.   
    8. #import "XNTabBar.h"  
    9. #import "XNTabBarButton.h"  
    10.   
    11. @interface XNTabBar ()  
    12. /** 
    13.  *  设置之前选中的按钮 
    14.  */  
    15. @property (nonatomic, weak) UIButton *selectedBtn;  
    16. @end  
    17.   
    18. @implementation XNTabBar  
    19.   
    20. /** 
    21.  *  在这个方法里写控件初始化的东西, 调用init方法时会调用 
    22.  */  
    23. //- (id)initWithFrame:(CGRect)frame {  
    24. //  if (self = [super initWithFrame:frame]) {  
    25. //      //添加按钮  
    26. //      for (int i = 0; i < 5; i++) { //取消掉特定的数字  
    27. //          //UIButton *btn = [[UIButton alloc] init];  
    28. //          XNTabBarButton *btn = [[XNTabBarButton alloc] init];  
    29. //  
    30. //          NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];  
    31. //          NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];  
    32. //  
    33. //          [btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];  
    34. //          [btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];  
    35. //  
    36. //          [self addSubview:btn];  
    37. //  
    38. //          btn.tag = i; //设置按钮的标记, 方便来索引当前的按钮,并跳转到相应的视图  
    39. //  
    40. //          //带参数的监听方法记得加"冒号"  
    41. //          [btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];  
    42. //  
    43. //          if (0 == i) {  
    44. //              [self clickBtn:btn];  
    45. //          }  
    46. //      }  
    47. //  }  
    48. //  return self;  
    49. //}  
    50.   
    51. - (void)addButtonWithImage:(UIImage *)image selectedImage:(UIImage *)selectedImage {  
    52.     UIButton *btn = [[UIButton alloc] init];  
    53.   
    54.     [btn setImage:image forState:UIControlStateNormal];  
    55.     [btn setImage:selectedImage forState:UIControlStateSelected];  
    56.   
    57.     [self addSubview:btn];  
    58.   
    59.     //带参数的监听方法记得加"冒号"  
    60.     [btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];  
    61.   
    62.     //如果是第一个按钮, 则选中(按顺序一个个添加)  
    63.     if (self.subviews.count == 1) {  
    64.         [self clickBtn:btn];  
    65.     }  
    66. }  
    67.   
    68. /**专门用来布局子视图, 别忘了调用super方法*/  
    69. - (void)layoutSubviews {  
    70.     [super layoutSubviews];  
    71.   
    72.     int count = self.subviews.count;  
    73.     for (int i = 0; i < count; i++) {  
    74.         //取得按钮  
    75.         UIButton *btn = self.subviews[i];  
    76.   
    77.         btn.tag = i; //设置按钮的标记, 方便来索引当前的按钮,并跳转到相应的视图  
    78.   
    79.         CGFloat x = i * self.bounds.size.width / count;  
    80.         CGFloat y = 0;  
    81.         CGFloat width = self.bounds.size.width / count;  
    82.         CGFloat height = self.bounds.size.height;  
    83.         btn.frame = CGRectMake(x, y, width, height);  
    84.     }  
    85. }  
    86.   
    87. /** 
    88.  *  自定义TabBar的按钮点击事件 
    89.  */  
    90. - (void)clickBtn:(UIButton *)button {  
    91.     //1.先将之前选中的按钮设置为未选中  
    92.     self.selectedBtn.selected = NO;  
    93.     //2.再将当前按钮设置为选中  
    94.     button.selected = YES;  
    95.     //3.最后把当前按钮赋值为之前选中的按钮  
    96.     self.selectedBtn = button;  
    97.   
    98.     //却换视图控制器的事情,应该交给controller来做  
    99.     //最好这样写, 先判断该代理方法是否实现  
    100.     if ([self.delegate respondsToSelector:@selector(tabBar:selectedFrom:to:)]) {  
    101.         [self.delegate tabBar:self selectedFrom:self.selectedBtn.tag to:button.tag];  
    102.     }  
    103.   
    104.     //4.跳转到相应的视图控制器. (通过selectIndex参数来设置选中了那个控制器)  
    105.     //self.selectedIndex = button.tag;  
    106. }  
    107.   
    108. @end  

    原先的XNTabBarController.m经过修改后,注释了原先的代码。

    [objc] view plaincopy在CODE上查看代码片派生到我的代码片
    1. //  
    2. //  XNTabBarController.m  
    3. //  
    4. //  Created by neng on 14-6-19.  
    5. //  Copyright (c) 2014年 neng. All rights reserved.  
    6. //  
    7.   
    8. #import "XNTabBarController.h"  
    9. #import "XNTabBarButton.h"  
    10. #import "XNTabBar.h"  
    11.   
    12. @interface XNTabBarController () <XNTabBarDelegate>  
    13. /** 
    14.  *  设置之前选中的按钮 
    15.  */  
    16. @property (nonatomic, weak) UIButton *selectedBtn;  
    17. @end  
    18.   
    19. @implementation XNTabBarController  
    20.   
    21. - (void)viewDidLoad {  
    22.     [super viewDidLoad];  
    23.     //下面两个方法在开发中是经常会用到的  
    24. //    NSLog(@"%s",__func__);  
    25. //    NSLog(@"%@",self.view.subviews); //能打印出所有子视图,和其frame  
    26. //  LogFun;  
    27. //  LogSubviews(self.view);  
    28.     //Hell  
    29.   
    30.   
    31.     //删除现有的tabBar  
    32.     CGRect rect = self.tabBar.bounds//这里要用bounds来加, 否则会加到下面去.看不见  
    33.     LogFrame(self.tabBar);  
    34.     //[self.tabBar removeFromSuperview];  //移除TabBarController自带的下部的条  
    35.   
    36.     //测试添加自己的视图  
    37.     XNTabBar *myView = [[XNTabBar alloc] init]; //设置代理必须改掉前面的类型,不能用UIView  
    38.     myView.delegate = self//设置代理  
    39.     myView.frame = rect;  
    40.     [self.tabBar addSubview:myView]; //添加到系统自带的tabBar上, 这样可以用的的事件方法. 而不必自己去写  
    41.       
    42.     //为控制器添加按钮  
    43.     for (int i=0; i<self.viewControllers.count; i++) { //根据有多少个子视图控制器来进行添加按钮  
    44.           
    45.         NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];  
    46.         NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];  
    47.           
    48.         UIImage *image = [UIImage imageNamed:imageName];  
    49.         UIImage *imageSel = [UIImage imageNamed:imageNameSel];  
    50.           
    51.         [myView addButtonWithImage:image selectedImage:imageSel];  
    52.     }  
    53.       
    54.   
    55. //    //添加按钮  
    56. //  for (int i = 0; i < 5; i++) {  
    57. //      //UIButton *btn = [[UIButton alloc] init];  
    58. //        XNTabBarButton *btn = [[XNTabBarButton alloc] init];  
    59. //  
    60. //      NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];  
    61. //      NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];  
    62. //  
    63. //      [btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];  
    64. //      [btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];  
    65. //  
    66. //      CGFloat x = i * myView.frame.size.width / 5;  
    67. //      btn.frame = CGRectMake(x, 0, myView.frame.size.width / 5, myView.frame.size.height);  
    68. //  
    69. //      [myView addSubview:btn];  
    70. //  
    71. //        btn.tag = i;//设置按钮的标记, 方便来索引当前的按钮,并跳转到相应的视图  
    72. //  
    73. //      //带参数的监听方法记得加"冒号"  
    74. //      [btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];  
    75. //  
    76. //      //设置刚进入时,第一个按钮为选中状态  
    77. //      if (0 == i) {  
    78. //          btn.selected = YES;  
    79. //          self.selectedBtn = btn;  //设置该按钮为选中的按钮  
    80. //      }  
    81. //  }  
    82. }  
    83.   
    84. /**永远别忘记设置代理*/  
    85. - (void)tabBar:(XNTabBar *)tabBar selectedFrom:(NSInteger)from to:(NSInteger)to {  
    86.     self.selectedIndex = to;  
    87. }  
    88.   
    89. /** 
    90.  *  自定义TabBar的按钮点击事件 
    91.  */  
    92. //- (void)clickBtn:(UIButton *)button {  
    93. //  //1.先将之前选中的按钮设置为未选中  
    94. //  self.selectedBtn.selected = NO;  
    95. //  //2.再将当前按钮设置为选中  
    96. //  button.selected = YES;  
    97. //  //3.最后把当前按钮赋值为之前选中的按钮  
    98. //  self.selectedBtn = button;  
    99. //  
    100. //    //4.跳转到相应的视图控制器. (通过selectIndex参数来设置选中了那个控制器)  
    101. //    self.selectedIndex = button.tag;  
    102. //}  
    103.   
    104. @end  

    自定义后的效果图:




    例子源码下载  http://download.csdn.net/detail/xn4545945/7572263

    转载请注明出处:http://blog.csdn.net/xn4545945  
  • 相关阅读:
    mysql 压缩备份 压缩还原 命令
    $' ': command not found
    CentOS7查看和关闭防火墙
    Linux系统运维故障排查
    使用netstat、lsof查看端口占用情况
    一道关于二叉树遍历的题目
    curl常用传参方式
    vm centos7中用NAT模式配置上网
    laravel使用过程中一些总结
    MySQL Replication
  • 原文地址:https://www.cnblogs.com/yuqingzhude/p/4836499.html
Copyright © 2020-2023  润新知