  
- 与其他自定义TabBarController的区别
- 集成后的效果
- 项目结构
- 使用CYLTabBarController
- 第一步:使用cocoaPods导入CYLTabBarController
- 第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组
- 第三步:将CYLTabBarController设置为window的RootViewController
- 第四步(可选):创建自定义的形状不规则加号按钮
- 补充说明
- 自定义 TabBar 样式
- 访问初始化好的 CYLTabBarController 对象
- 在 Swift 项目中使用 CYLTabBarController
- 源码实现原理
- Q-A
| - | 特点 | 解释 |
|---|---|---|
| 1 | 低耦合 | 与业务完全分离,最低只需传两个数组即可完成主流App框架搭建 |
| 2 | TabBar 以及 TabBar 内的 TabBarItem 均使用系统原生的控件 |
因为使用原生的控件,并非 UIButton 或 UIView 。好处如下: 1. 无需反复调“间距位置等”来接近系统效果。 2. 在push到下一页时 TabBar 的隐藏和显示之间的过渡效果跟系统一致(详见“ 集成后的效果 ”部分,给出了效果图) 3. 原生控件,所以可以使用诸多系统API,比如:可以使用 [UITabBar appearance]; 、 [UITabBarItem appearance]; 设置样式。(详见“补充说明 ”部分,给出了响应代码示例) |
| 3 | 自动监测是否需要添加“加号”按钮,并能自动设置位置 | CYLTabBarController 既支持类似微信的“中规中矩”的 TabBarController 样式,并且默认就是微信这种样式,同时又支持类似“微博”或“淘宝闲鱼”这种具有不规则加号按钮的 TabBarController 。想支持这种样式,只需自定义一个加号按钮,CYLTabBarController 能检测到它的存在并自动将 tabBar 排序好,无需多余操作,并且也预留了一定接口来满足自定义需求。“加号”按钮的样式、frame均在自定义的类中独立实现,不会涉及tabbar相关设置。 |
| 4 | 即使加号按钮超出了tabbar的区域,超出部分依然能响应点击事件 | 红线内的区域均能响应tabbar相关的点击事件,![]() |
| 5 | 允许指定加号按钮位置 | 效果如下:![]() |
| 6 | 支持CocoaPods | 容易集成 |
| 7 | 支持Swift项目导入 | 兼容 |
(学习交流群:541317935)
| 既支持默认样式 | 同时也支持创建自定义的形状不规则加号按钮 |
|---|---|
![]() |
![]() |
| 本仓库配套Demo的效果: | 另一个Demo 使用CYLTabBarController实现了微博Tabbar框架,效果如下 |
|---|---|
![]() |
![]() |
做下说明:
├── CYLTabBarController #核心库文件夹,如果不使用 CocoaPods 集成,请直接将这个文件夹下拖拽带你的项目中
└── Example
└── Classes
├── Module #模块类文件夹
│ ├── Home
│ ├── Message
│ ├── Mine
│ └── SameCity
└── View #这里放着 CYLPlusButton 的子类 CYLPlusButtonSubclass,演示了如何创建自定义的形状不规则加号按钮
四步完成主流App框架搭建:
- 第一步:使用cocoaPods导入CYLTabBarController
- 第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组
- 第三步:将CYLTabBarController设置为window的RootViewController
- 第四步(可选):创建自定义的形状不规则加号按钮
在 Podfile 中进行如下导入:
pod 'CYLTabBarController'然后使用 cocoaPods 进行安装:
如果尚未安装 CocoaPods, 运行以下命令进行安装:
gem install cocoapods安装成功后就可以安装依赖了:
建议使用如下方式:
# 禁止升级CocoaPods的spec仓库,否则会卡在 Analyzing dependencies ,非常慢
pod update --verbose --no-repo-update如果提示找不到库,则可去掉 --no-repo-update
pod update- (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;
}- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/* *省略部分: * */
[self.window setRootViewController:self.tabBarController];
/* *省略部分: * */
return YES;
}创建一个继承于 CYLPlusButton 的类,要求和步骤:
-
实现
CYLPlusButtonSubclassing协议 -
子类将自身类型进行注册,一般可在
application的applicationDelegate方法里面调用[YourClass registerSubClass]或者在子类的+load方法中调用:
+(void)load {
[super registerSubclass];
}协议提供了两个可选方法:
+ (NSUInteger)indexOfPlusButtonInTabBar;
+ (CGFloat)multiplerInCenterY;作用分别是:
+ (NSUInteger)indexOfPlusButtonInTabBar;用来自定义加号按钮的位置,如果不实现默认居中,但是如果 tabbar 的个数是奇数则必须实现该方法,否则 CYLTabBarController 会抛出 exception 来进行提示。
主要适用于如下情景:
+ (CGFloat)multiplerInCenterY;该方法是为了调整自定义按钮中心点Y轴方向的位置,建议在按钮超出了 tabbar 的边界时实现该方法。返回值是自定义按钮中心点Y轴方向的坐标除以 tabbar 的高度,如果不实现,会自动进行比对,预设一个较为合适的位置,如果实现了该方法,预设的逻辑将失效。
详见Demo中的 CYLPlusButtonSubclass 类的实现。
另外,如果加号按钮超出了边界,一般需要手动调用如下代码取消 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];效果如下,
同时你也可以顺便测试下 CYLTabBarController 的这一个特性:
即使加号按钮超出了tabbar的区域,超出部分依然能响应点击事件
并且你可以在项目中的任意位置读取到 PlusButton 的宽度,借助 CYLTabBarController.h 定义的 CYLPlusButtonWidth 这个extern。可参考 +[CYLTabBarControllerConfig customizeTabBarAppearance:] 里的用法。
如果想更进一步的自定义 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;
}有两种方式:
第一种:
对于 UIViewController :
UITabBarController *tabBarController = (UITabBarController *)self.view.window.rootViewController;对于 UIView :
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;对于任意 NSObject 对象:
id<UIApplicationDelegate> delegate = ((id<UIApplicationDelegate>)[[UIApplication sharedApplication] delegate]);
UIWindow *window = delegate.window;
CYLTabBarController *tabbarController = (CYLTabBarController *)window.rootViewController;第二种:
CYLTabBarController.h 中为 UIViewController 提供了分类方法 -cyl_tabBarController ,所以在 UIViewController 类中,一行代码就可以访问到一个初始化好的 CYLTabBarController 对象,-cyl_tabBarController 的作用你可以这样理解:与获取单例对象的 +shareInstance 方法作用一样。
接口如下:
// CYLTabBarController.h
@interface UIViewController (CYLTabBarController)
/**
* The nearest ancestor in the view controller hierarchy that is a tab bar controller. (read-only)
*/
@property (nonatomic, readonly) CYLTabBarController *cyl_tabBarController;
@end用法:
//导入 CYLTabBarController.h
#import "CYLTabBarController.h"
- (void)viewDidLoad {
[super viewDidLoad];
CYLTabBarController *tabbarController = [self cyl_tabBarController];
/*...*/
}参考: 《从头开始swift2.1 仿搜材通项目(三) 主流框架Tabbed的搭建》
参考: 《[Note] CYLTabBarController》
更多文档信息可查看 CocoaDocs:CYLTabBarController 。
Q:为什么放置6个TabBarItem会显示异常?
A:
Apple 规定:
一个
TabBar上只能出现最多5个TabBarItem,第六个及更多的将不被显示。
另外注意,Apple检测的是 UITabBarItem 及其子类,所以放置“加号按钮”,这是 UIButton 不在“5个”里面。
最多只能添加5个 TabBarItem ,也就是说加上“加号按钮”,一共最多在一个 TabBar 上放置6个控件。否则第6个及之后出现 TabBarItem 会被自动屏蔽掉。而且就Apple的审核机制来说,超过5个也会被直接拒绝上架。
A:我已经在 Demo 中添加了如何实现该功能的代码:
详情见 CYLTabBarControllerConfig 类中下面方法的实现:
/**
* 更多TabBar自定义设置:比如:tabBarItem 的选中和不选中文字和背景图片属性、tabbar 背景图片属性
*/
- (void)customizeTabBarAppearance;
Q: 当 ViewController 设置的 self.title 和 tabBarItemsAttributes 中对应的 title 不一致的时候,会出现如图的错误,排序不对了
A:在 v1.0.7 版本中已经修复了该 bug,但是也需要注意:
请勿使用 self.title = @"同城"; 这种方式,请使用 self.navigationItem.title = @"同城";
self.title = @"同城"; 这种方式,如果和 tabBarItemsAttributes 中对应的 title 不一致的时候可能会导致如下现象(不算 bug,但看起来也很奇怪):
规则如下:
self.navigationItem.title = @"同城"; //✅sets navigation bar title.The right way to set the title of the navigation
self.tabBarItem.title = @"同城23333"; //❌sets tab bar title. Even the `tabBarItem.title` changed, this will be ignored in tabbar.
self.title = @"同城1"; //❌sets both of these. Do not do this‼️‼️ This may cause something strange like this : http://i68.tinypic.com/282l3x4.jpg
Q : 当使用这个方法时 -[UIViewController cyl_jumpToOtherTabBarControllerItem:(Class)ClassType performSelector:arguments:returnValue:] 会出现如下的黑边问题。
A: 这个时 iOS 系统的BUG,经测试iOS9.3已经修复了,如果在更早起版本中出现了,可以通过下面将 rootWindow的背景色改为白色来避免:比如你可以这样:
[(CYLTabBarController *)self.tabBarController rootWindow].backgroundColor = [UIColor whiteColor];(更多iOS开发干货,欢迎关注 微博@iOS程序犭袁 )
Posted by 微博@iOS程序犭袁
原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0











