美文网首页iOS开发文章iOSiOS开发指南
【低耦合集成TabBarController】最低只需传两个数组

【低耦合集成TabBarController】最低只需传两个数组

作者: iOS程序犭袁 | 来源:发表于2015-10-26 01:18 被阅读2722次

    CYLTabBarController【低耦合集成TabBarController】

    <p align="center">


    bitHound
    enter image description here 5 允许指定加号按钮位置 效果如下:</p> enter image description here </p>Airbnb-app效果:</p> enter image description here 6 支持让 TabBarItem 仅显示图标,并自动使图标垂直居中,支持自定义TabBar高度 效果可见Airbnb-app效果,或者下图</p> enter image description here enter image description here

    支持横竖屏


    enter image description here
    本仓库配套Demo的效果: 另一个Demo 使用CYLTabBarController实现了微博Tabbar框架,效果如下
    enter image description here enter image description here

    项目结构

    enter image description here

    做下说明:

    
    ├── CYLTabBarController  #核心库文件夹,如果不使用 CocoaPods 集成,请直接将这个文件夹拖拽带你的项目中
    └── Example
       └── Classes
           ├── Module       #模块类文件夹
           │   ├── Home
           │   ├── Message
           │   ├── Mine
           │   └── SameCity
           └── View         #这里放着 CYLPlusButton 的子类 CYLPlusButtonSubclass,演示了如何创建自定义的形状不规则加号按钮
           
           
    

    使用CYLTabBarController

    四步完成主流App框架搭建:

    1. 第一步:使用CocoaPods导入CYLTabBarController
    2. 第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组
    3. 第三步:将CYLTabBarController设置为window的RootViewController
    4. 第四步(可选):创建自定义的形状不规则加号按钮

    第一步:使用CocoaPods导入CYLTabBarController

    Podfile 中进行如下导入:

    pod 'CYLTabBarController'
    

    然后使用 cocoaPods 进行安装:

    如果尚未安装 CocoaPods, 运行以下命令进行安装:

    gem install cocoapods
    

    安装成功后就可以安装依赖了:

    建议使用如下方式:

    # 禁止升级CocoaPods的spec仓库,否则会卡在 Analyzing dependencies ,非常慢 
    pod update --verbose --no-repo-update
    

    如果提示找不到库,则可去掉 --no-repo-update

    pod update
    

    第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组

    - (void)setupViewControllers {
       CYLHomeViewController *firstViewController = [[CYLHomeViewController alloc] init];
       UIViewController *firstNavigationController = [[UINavigationController alloc]
                                                      initWithRootViewController:firstViewController];
       
       CYLSameFityViewController *secondViewController = [[CYLSameFityViewController alloc] init];
       UIViewController *secondNavigationController = [[UINavigationController alloc]
                                                       initWithRootViewController:secondViewController];
       
    
       CYLTabBarController *tabBarController = [[CYLTabBarController alloc] init];
       [self customizeTabBarForController:tabBarController];
       
       [tabBarController setViewControllers:@[
                                              firstNavigationController,
                                              secondNavigationController,
                                              ]];
       self.tabBarController = tabBarController;
    }
    
    /*
    *
    在`-setViewControllers:`之前设置TabBar的属性,
    *
    */
    - (void)customizeTabBarForController:(CYLTabBarController *)tabBarController {
       
       NSDictionary *dict1 = @{
                               CYLTabBarItemTitle : @"首页",
                               CYLTabBarItemImage : @"home_normal",
                               CYLTabBarItemSelectedImage : @"home_highlight",
                               };
       NSDictionary *dict2 = @{
                               CYLTabBarItemTitle : @"同城",
                               CYLTabBarItemImage : @"mycity_normal",
                               CYLTabBarItemSelectedImage : @"mycity_highlight",
                               };
    
       NSArray *tabBarItemsAttributes = @[ dict1, dict2 ];
       tabBarController.tabBarItemsAttributes = tabBarItemsAttributes;
    }
    

    第三步:将CYLTabBarController设置为window的RootViewController

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    /* *省略部分:   * */
       [self.window setRootViewController:self.tabBarController];
    /* *省略部分:   * */
       return YES;
    }
    

    第四步(可选):创建自定义的形状不规则加号按钮

    创建一个继承于 CYLPlusButton 的类,要求和步骤:

    1. 实现 CYLPlusButtonSubclassing 协议

    2. 子类将自身类型进行注册,一般可在 applicationapplicationDelegate 方法里面调用 [YourClass registerSubClass] 或者在子类的 +load 方法中调用:

    +(void)load {
       [super registerSubclass];
    }
    

    协议提供了可选方法:

    + (NSUInteger)indexOfPlusButtonInTabBar;
    + (CGFloat)multiplerInCenterY;
    + (UIViewController *)plusChildViewController;
    

    作用分别是:

    + (NSUInteger)indexOfPlusButtonInTabBar;
    

    用来自定义加号按钮的位置,如果不实现默认居中,但是如果 tabbar 的个数是奇数则必须实现该方法,否则 CYLTabBarController 会抛出 exception 来进行提示。

    主要适用于如下情景:

    enter image description here

    Airbnb-app效果:

    enter image description here
    + (CGFloat)multiplerInCenterY;
    

    该方法是为了调整自定义按钮中心点Y轴方向的位置,建议在按钮超出了 tabbar 的边界时实现该方法。返回值是自定义按钮中心点Y轴方向的坐标除以 tabbar 的高度,如果不实现,会自动进行比对,预设一个较为合适的位置,如果实现了该方法,预设的逻辑将失效。

    详见Demo中的 CYLPlusButtonSubclass 类的实现。

    + (UIViewController *)plusChildViewController;
    

    详见: 点击 PlusButton 跳转到指定 UIViewController

    另外,如果加号按钮超出了边界,一般需要手动调用如下代码取消 tabbar 顶部默认的阴影,可在 AppDelegate 类中调用:

       //去除 TabBar 自带的顶部阴影
       [[UITabBar appearance] setShadowImage:[[UIImage alloc] init]];
    

    如何调整、自定义 PlusButton 与其它 TabBarItem 的宽度?

    CYLTabBarController 规定:

    TabBarItem 宽度 =  ( TabBar 总宽度 -  PlusButton 宽度  ) / (TabBarItem 个数)
    

    所以想自定义宽度,只需要修改 PlusButton 的宽度即可。

    比如你就可以在 Demo中的 CYLPlusButtonSubclass.m 类里:

    [button sizeToFit]; 
    

    改为

    button.frame = CGRectMake(0.0, 0.0, 250, 100);
    button.backgroundColor = [UIColor redColor];
    

    效果如下,

    enter image description here

    同时你也可以顺便测试下 CYLTabBarController 的这一个特性:

    即使加号按钮超出了tabbar的区域,超出部分依然能响应点击事件

    并且你可以在项目中的任意位置读取到 PlusButton 的宽度,借助 CYLTabBarController.h 定义的 CYLPlusButtonWidth 这个extern。可参考 +[CYLTabBarControllerConfig customizeTabBarAppearance:] 里的用法。

    补充说明

    自定义 TabBar 样式

    如果想更进一步的自定义 TabBar 样式可在 -application:didFinishLaunchingWithOptions: 方法中设置

    /**
    *  tabBarItem 的选中和不选中文字属性、背景图片
    */
    - (void)customizeInterface {
       
       // 普通状态下的文字属性
       NSMutableDictionary *normalAttrs = [NSMutableDictionary dictionary];
       normalAttrs[NSForegroundColorAttributeName] = [UIColor grayColor];
       
       // 选中状态下的文字属性
       NSMutableDictionary *selectedAttrs = [NSMutableDictionary dictionary];
       selectedAttrs[NSForegroundColorAttributeName] = [UIColor darkGrayColor];
       
       // 设置文字属性
       UITabBarItem *tabBar = [UITabBarItem appearance];
       [tabBar setTitleTextAttributes:normalAttrs forState:UIControlStateNormal];
       [tabBar setTitleTextAttributes:selectedAttrs forState:UIControlStateSelected];
       
       // 设置背景图片
       UITabBar *tabBarAppearance = [UITabBar appearance];
       [tabBarAppearance setBackgroundImage:[UIImage imageNamed:@"tabbar_background"]];
    }
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    /* *省略部分:   * */
       [self.window makeKeyAndVisible];
       [self customizeInterface];
       return YES;
    }
    

    横竖屏适配

    TabBar 横竖屏适配时,如果你添加了 PlusButton,且适配时用到了 TabBarItem 的宽度, 不建议使用系统的UIDeviceOrientationDidChangeNotification , 请使用库里的 CYLTabBarItemWidthDidChangeNotification 来更新 TabBar 布局,最典型的场景就是,根据 TabBarItem 在不同横竖屏状态下的宽度变化来切换选中的TabBarItem 的背景图片。Demo 里 CYLTabBarControllerConfig.m 给出了这一场景的用法:

    CYLTabBarController.h 中提供了 CYLTabBarItemWidth 这一extern常量,并且会在 TabBarItem 的宽度发生变化时,及时更新该值,所以用法就如下所示:

    - (void)updateTabBarCustomizationWhenTabBarItemWidthDidUpdate {
       void (^deviceOrientationDidChangeBlock)(NSNotification *) = ^(NSNotification *notification) {
           [self tabBarItemWidthDidUpdate];
       };
       [[NSNotificationCenter defaultCenter] addObserverForName:CYLTabBarItemWidthDidChangeNotification
                                                         object:nil
                                                          queue:[NSOperationQueue mainQueue]
                                                     usingBlock:deviceOrientationDidChangeBlock];
    }
    
    - (void)tabBarItemWidthDidUpdate {
       UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
       if ((orientation == UIDeviceOrientationLandscapeLeft) || (orientation == UIDeviceOrientationLandscapeRight)) {
           NSLog(@"Landscape Left or Right !");
       } else if (orientation == UIDeviceOrientationPortrait){
           NSLog(@"Landscape portrait!");
       }
       CGSize selectionIndicatorImageSize = CGSizeMake(CYLTabBarItemWidth, [self cyl_tabBarController].tabBar.bounds.size.height);
       [[self cyl_tabBarController].tabBar setSelectionIndicatorImage:[[self class]
                                                                       imageFromColor:[UIColor yellowColor]
                                                                       forSize:selectionIndicatorImageSize
                                                                       withCornerRadius:0]];
    }
    
    enter image description here

    访问初始化好的 CYLTabBarController 对象

    对于任意 NSObject 对象:

    CYLTabBarController.h 中为 NSObject 提供了分类方法 -cyl_tabBarController ,所以在任意对象中,一行代码就可以访问到一个初始化好的 CYLTabBarController 对象,-cyl_tabBarController 的作用你可以这样理解:与获取单例对象的 +shareInstance 方法作用一样。

    接口如下:

    // CYLTabBarController.h
    
    @interface NSObject (CYLTabBarController)
    
    /**
    * If `self` is kind of `UIViewController`, this method will return the nearest ancestor in the view controller hierarchy that is a tab bar controller. If `self` is not kind of `UIViewController`, it will return the `rootViewController` of the `rootWindow` as long as you have set the `CYLTabBarController` as the  `rootViewController`. Otherwise return nil. (read-only)
    */
    @property (nonatomic, readonly) CYLTabBarController *cyl_tabBarController;
    
    @end
    

    用法:

    //导入 CYLTabBarController.h
    #import "CYLTabBarController.h"
    
    - (void)viewDidLoad {
       [super viewDidLoad];
       CYLTabBarController *tabbarController = [self cyl_tabBarController];
       /*...*/
    }
    

    点击 PlusButton 跳转到指定 UIViewController

    提供了一个协议方法来完成本功能:

    enter image description here

    实现该方法后,能让 PlusButton 的点击效果与跟点击其他 UITabBarButton 效果一样,跳转到该方法指定的 UIViewController 。

    注意:必须同时实现 +indexOfPlusButtonInTabBar 来指定 PlusButton 的位置。

    遵循两个协议:

    enter image description here

    让TabBarItem仅显示图标,并使图标垂直居中

    要想实现该效果,只需要在设置 tabBarItemsAttributes该属性时不传 title 即可。

    比如:在Demo的基础上,注释掉图中红框部分:


    enter image description here
    注释前 注释后
    enter image description here enter image description here

    可以通过这种方式来达到 Airbnb-app 的效果:

    enter image description here

    如果想手动设置偏移量来达到该效果:
    可以在 -setViewControllers: 方法前设置 CYLTabBarControllerimageInsetstitlePositionAdjustment 属性

    这里注意:设置这两个属性后,TabBar 中所有的 TabBarItem 都将被设置。并且第一种做法的逻辑将不会执行,也就是说该做法优先级要高于第一种做法。

    做法如下:


    enter image description here

    但是想达到Airbnb-app的效果只有这个接口是不行的,还需要自定义下 TabBar 的高度,你需要设置 CYLTabBarControllertabBarHeight 属性。你可以在Demo的 CYLTabBarControllerConfig.m 中的 -customizeTabBarAppearance: 方法中设置。

    注:“仅显示图标,并使图标垂直居中”这里所指的“图标”,其所属的类是私有类: UITabBarSwappableImageView,所以 CYLTabBarController 在相关的接口命名时会包含 SwappableImageView 字样。

    在 Swift 项目中使用 CYLTabBarController

    参考: 《从头开始swift2.1 仿搜材通项目(三) 主流框架Tabbed的搭建》

    这里注意,文章的示例代码有问题,少了设置 PlusButton 大小的代码:
    这将导致 PlusButton 点击事件失效,具体修改代码如下:


    enter image description here

    源码实现原理

    参考: 《[Note] CYLTabBarController》

    更多文档信息可查看 CocoaDocs:CYLTabBarController

    Q-A

    Q:为什么放置6个TabBarItem会显示异常?

    A:

    Apple 规定:

    一个 TabBar 上只能出现最多5个 TabBarItem ,第六个及更多的将不被显示。

    另外注意,Apple检测的是 UITabBarItem 及其子类,所以放置“加号按钮”,这是 UIButton 不在“5个”里面。

    最多只能添加5个 TabBarItem ,也就是说加上“加号按钮”,一共最多在一个 TabBar 上放置6个控件。否则第6个及之后出现 TabBarItem 会被自动屏蔽掉。而且就Apple的审核机制来说,超过5个也会被直接拒绝上架。

    Q: 如何实现添加选中背景色的功能 ,像下面这样:


    enter image description here

    A: 这个是 iOS 系统的BUG,经测试iOS9.3已经修复了,如果在更早起版本中出现了,可以通过下面将 rootWindow 的背景色改为白色来避免:比如你可以 Appdelegate 类里这样设置:

    //#import "CYLTabBarController.h"
       [[self cyl_tabBarController] rootWindow].backgroundColor = [UIColor whiteColor];
    

    Q:我现在已经做好了一个比较简单的中间凸起的 icon 但是超过了49这个高度的位置是不能效应的 我想请问你的demo哪个功能是可以使我超出的范围也可以响应的呢?

    A: 这个是自动做的,但是 CYLTabBarController 只能保证的是:只要是 UIButton 的 frame 区域内就能响应。

    请把 button 的背景颜色设置为显眼的颜色,比如红色,比如像下面的plus按钮,红色部分是能接收点击事件的,但是超出了红色按钮的,黄色的图片区域,依然是无法响应点击事件的。

    enter image description here

    这是因为,在响应链上,UIControl 能响应点击事件, UIImage 无法响应。

    (更多iOS开发干货,欢迎关注 微博@iOS程序犭袁


    Posted by 微博@iOS程序犭袁
    原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
    <p align="center"><a href="http://weibo.com/u/1692391497?s=6uyXnP" target="_blank">

    </a></a>

    相关文章

      网友评论

      • feibum:不知道什么原因 集成后不显示PlusButton 完全按照文档去写的
      • 6cddee706b65:CYLTabBar可以加载网络图片吗?怎么加载呢?
      • 63333aa9cb00:楼主 大神
      • 侠永:能不能获取到 TabBarItem ???。我这有个需求是 点击“我的” 判断是否登录,没登录 去登录页面, 登录 去我的页面。 这个怎么弄啊?? 谢谢
        酒红色T恤:@侠永 从Pods上加载的控制器好像没有delegate,怎么设置啊
      • 437aff410919:想请教下,就是好比如APP有消息模块。一般进去到这个APP 消息模块就会显示有多少个消息未读。而这个tabbarcontroller,并没有一开始就加载。需要点击到指定的tabbaritem才会调用到那个控制器的viewdidload。如果想要这样子实现一进来 其他控制器都还没点击的时候就可以显示有多少个未读消息需要怎么做?
      • 商丘彭于晏:假如我在 首页 点击某个按钮如何跳转到 消息 这个模块
        63333aa9cb00:改变 tabbar 的selectedItemIndex 就可以了吧
      • 桐生一猫:我想要用这个tabbar,但是要搞个侧滑的界面,请问有解吗??? :flushed: :flushed:
        779b68e64744:我也想知道, 如何像qq那样搞呢..
        桐生一猫:@iOS程序犭袁 像QQ那种
        iOS程序犭袁:@桐生一猫 详细描述下需求
      • JackMayx:哥你好!我最近在研究你这个东西!有一个问题是,我集成后那个中间的按钮点击事件没有反应!我在swift中这样写的!
        ///中间的资金按钮
        class PlusButtonSubclass : CYLPlusButton,CYLPlusButtonSubclassing{

        class func plusButton() -> AnyObject! {

        let button:PlusButtonSubclass = PlusButtonSubclass()
        button.setImage(UIImage(named: "zhuangtai"), forState: UIControlState.Normal)

        button.titleLabel!.textAlignment = NSTextAlignment.Center;
        button.adjustsImageWhenHighlighted = false;
        button.addTarget(button, action: #selector(PlusButtonSubclass.buttonClicked), forControlEvents: UIControlEvents.TouchUpInside)
        return button
        }

        //点击事件
        func buttonClicked()
        {
        print("hello")
        }
        点击事件没响应,求指教!在线等
        iOS程序犭袁:@如风丶也如剑 这个是因为你没有设置按钮的宽高, 按照文档操作下就可以了 --》 https://github.com/ChenYilong/CYLTabBarController#在-swift-项目中使用-cyltabbarcontroller
      • Ashen_:这个tabbarController有点炫酷

      本文标题:【低耦合集成TabBarController】最低只需传两个数组

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