跳至正文 探索 熱議 搜尋 熱門 我的CYLTabBarController — nomorevibe
探索專案 › 開發工具 › CYLTabBarController
CYLTabBarController [EN]It is an iOS UI module library for adding animation to iOS tabbar items and icons with Lottie, Liquid Glass and adding a bigger center UITabBar Item. [CN]【中国特色 TabBar】一行代码实现 Lottie 动画TabBar,支持中间带
翻譯準備中
開發工具 · ★ 7,055 · Swift · Ruby · GitHub @ChenYilong · 自行安裝 · 營運者未確認
開啟 GitHub 儲存庫 複製安裝提示詞 貼到 Claude 或 ChatGPT,可取得適合你環境的安裝指引。
檢視提示詞 安裝提示詞 分享
使用方式 自行安裝 在使用者環境中執行
最近程式碼更新 10月30日 活躍儲存庫 最新版本 1.99.67↗ iOS27 iPhone Duo Supports landscape and portrait layouts. · 10月27日
貢獻者 13 人 分支 1,456
nomorevibe 收錄 10月30日 儲存庫建立於 2015年10月 語言組成
Swift 97.3% Ruby 2.6% Shell 0.2% 追蹤
介紹 [EN]It is an iOS UI module library for adding animation to iOS tabbar items and icons with Lottie, Liquid Glass and adding a bigger center UITabBar Item. [CN]【中国特色 TabBar】一行代码实现 Lottie 动画TabBar,支持中间带+号的TabBar样式,自带红点角标,支持动态刷新。【iOS27 & Dark Mode & iPhone 18 & iPhone Duo tested】
翻譯準備中
取自儲存庫 README
追蹤
README
[CN]CYLTabBarController【一行代码实现 Lottie 动画 TabBar】iOS27+ Tested
[EN]CYLTabBarController [An animated tabBar supported by Lottie with one line of code]
[CN]阅读须知
[EN]Before Reading
[CN]最新版本预览
[EN]Preview of the latest version
Preview of the latest version on iOS 27+
[CN]iOS 27 和 iPhone Duo 适配
[EN]iOS 27 and iPhone Duo support
CYLTabBarController 现已适配 iOS 27,新增如下功能:
CYLTabBarController now supports iOS 27 with the following improvements:
现在已适配 iPhone Duo 的横向布局与竖向布局,请更新至 CYLTabBarController 1.99.66 查看。
It also supports both landscape and portrait layouts on iPhone Duo. Update to CYLTabBarController 1.99.66 to try it.
CYLTabBarController 现已适配 iOS 27 和 iPhone Duo,更新内容如下:
CYLTabBarController now supports iOS 27 and iPhone Duo with the following features:
✅ Supports landscape and portrait layouts.
✅ 支持扁平样式与液态玻璃样式 ✅ Supports flat and Liquid Glass styles.
✅ 所有样式均支持加号按钮居中显示。 ✅ The plus button can be centered in every style.
✅ 零代码适配:已经接入 CYLTabBar 液态玻璃样式或扁平样式的代码,无需修改代码,更新版本即可适配 iPhone Duo。 ✅ Zero-code adaptation: apps already using the CYLTabBar Liquid Glass or flat style require no code changes to support iPhone Duo.
✅ 审核友好,适配代码均为纯原生公开 API,无审核风险。 ✅ Review-friendly: the adaptation uses only public native APIs.
请更新 CYLTabBarController 1.99.66 查看演示:
Update to CYLTabBarController 1.99.66 to see the demo:
中文 English ✅ iOS 27 下无需新增代码即可启用扁平风格;保留 UIDesignRequiresCompatibility 时会自动切换到扁平样式。 ✅ Enable the flat style on iOS 27 without adding code; UIDesignRequiresCompatibility automatically selects the flat style. ✅ 扁平风格作为独立组件集成,降低耦合并减小包体积。 ✅ The flat style is integrated as an independent component for lower coupling and a smaller package size. ✅ 扁平风格与液态玻璃样式共享 API,只需修改样式属性即可切换。 ✅ The flat and Liquid Glass styles share the same APIs; switch styles by changing the appearance property. ✅ 支持运行期间在两种样式之间切换,适合 A/B 测试和灰度发布。 ✅ Switch between styles at runtime for A/B testing and staged rollout. ✅ 液态玻璃样式继承自 UITabBar,支持系统样式设置,并提供 PlusButton。 ✅ The Liquid Glass style inherits from UITabBar, supports system appearance settings, and adds PlusButton support. ✅ 支持同时展示 Lottie 动画、液态玻璃效果和红点角标动画。 ✅ Display Lottie animations, Liquid Glass effects, and animated badges together. ✅ 建议升级到 1.99.41 或更高版本进行 iOS 27 适配。 ✅ Upgrade to 1.99.41 or later for iOS 27 support. CYLTabBarController 现已支持在 iOS 26 上实现以下效果,请更新至 1.99.39 或更高版本。 CYLTabBarController supports the following features on iOS 26. Update to version 1.99.39 or later:
中文 English ✅ 同时展示 Lottie 动画与液态玻璃效果。 ✅ Display Lottie animations and the Liquid Glass effect together. ✅ 支持将 PlusButton 居中显示在液态玻璃效果上,并保留旧版本的按钮逻辑。 ✅ Center PlusButton over the Liquid Glass effect while preserving the previous button behavior. ✅ 液态玻璃效果不使用私有 API,适合 Apple 审核。 ✅ Liquid Glass uses no private APIs and is suitable for App Store review. ✅ 使用纯原生液态玻璃效果,支持系统对相关属性的设置。 ✅ Use a native Liquid Glass effect and support the system appearance settings. ✅ 面向企业生产环境的开源解决方案。 ✅ An open-source solution suitable for production environments. ✅ 对现有集成友好,升级通常只需少量代码修改。 ✅ Existing integrations can usually be upgraded with minimal code changes. ✅ 不依赖 UI 兼容模式,适合 iOS 27 审核。 ✅ Does not depend on UI compatibility mode and is review-friendly on iOS 27. ✅ GitHub:https://github.com/ChenYilong/CYLTabBarController ✅ GitHub: https://github.com/ChenYilong/CYLTabBarController
1.99.39 版本现已支持在 iOS 26 运行期间增加或删除加号按钮。效果见下方演示,欢迎访问 Demo 进行尝试:
Version 1.99.39 supports adding or removing the plus button at runtime on iOS 26. See the demo below or visit the Demo to try it:
[CN]谁在使用?已上架 App 列表
[EN]Who is using it? Published apps
[CN]导航
[EN]CONTENTS
[CN]与其他自定义 TabBarController 的区别
[EN]Comparison with other libraries 中文 English 一行代码支持 Lottie 动画 TabBar 使用方法 One line of code enables an animated TabBar with Lottie. Usage 低耦合,易删除 TabBar 配置与业务代码完全分离;PlusButton 由独立子类管理。Loosely coupled and easy to remove. TabBar configuration is independent from business code, and PlusButton is managed by a separate subclass.使用系统原生控件 TabBar 和 TabBarItem 保持系统行为,并支持外观 API。Uses native system controls. TabBar and TabBarItem preserve system behavior and support the appearance APIs.自动管理 PlusButton 自动检测 PlusButton、计算位置并完成布局;按钮样式和 frame 由自定义类实现。Automatically manages PlusButton. The library detects the PlusButton, calculates its position, and lays it out automatically.支持动态更新 可以动态添加或删除 PlusButton,并更新 TabBar 样式。Supports runtime updates. Add or remove the PlusButton and update the TabBar appearance at runtime.支持超出 TabBar 区域点击 PlusButton 超出 TabBar 的部分仍可响应点击。Supports taps outside the TabBar bounds. The portion of PlusButton extending beyond the TabBar can still receive taps.支持指定 PlusButton 位置 可指定 PlusButton 的位置,并支持 Airbnb 风格布局。Supports a custom PlusButton position. Place the PlusButton at a custom index and support Airbnb-style layouts.仅显示图标并垂直居中 不设置标题即可只显示图标,并可自定义 TabBar 高度。Icon-only, vertically centered items. Omit the title to show only icons and customize the TabBar height.支持自定义角标 View 可以使用自定义 View 展示角标。Supports custom badge views. Use a custom view to display badges.支持多 TabBar 嵌套 可嵌套多个 TabBar,并指定 PlusButton 所属的 context。Supports nested TabBars. Nest multiple TabBars and associate a PlusButton with a specific context.支持 CocoaPods 和 Swift 易于集成,并兼容 Swift 项目。Supports CocoaPods and Swift. Easy to integrate and compatible with Swift projects.支持横竖屏 自动适配不同屏幕方向。Supports portrait and landscape orientations. Layout adapts to both orientations.
学习交流群:515295083
Learning group: 515295083.
[CN]集成后的效果
[EN]Results after integration 中文 English 默认样式 Default style 自定义不规则 PlusButton Custom irregular PlusButton
Supports portrait and landscape orientations.
[CN]项目结构
[EN]Project structure 说明:
The directory structure is organized as follows:
├── CYLTabBarController # 核心库文件夹;不使用 CocoaPods 时可直接拖入项目
└── Example
└── Classes
├── Module # 模块类文件夹 / Module classes
│ ├── Home
│ ├── Message
│ ├── Mine
│ └── SameCity
└── View # CYLPlusButton 子类;演示自定义不规则 PlusButton
中文 English 四步完成主流 App 框架搭建: Build a mainstream app structure in four steps:
[CN]第一步:使用 CocoaPods 导入 CYLTabBarController
[EN]Step 1: Import CYLTabBarController with CocoaPods
[CN]1. 安装 CocoaPods
[EN]1. Install CocoaPods 中文 English 如果您的机器上已经安装了 CocoaPods,直接进入下一步即可。 If CocoaPods is already installed, continue to the next step.
中文 English 如果网络环境允许直接访问 RubyGems,请在终端运行: If RubyGems is directly accessible, run:
sudo gem install cocoapods
中文 English 如果无法直接访问 RubyGems,可以使用 Ruby China 镜像: If RubyGems is unavailable, use the Ruby China mirror:
中文 English 在终端依次运行以下命令: Run the following commands in sequence in the terminal:
gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/ sudo gem install cocoapods
[CN]2. 查询 CocoaPods 源
[EN]2. Search the CocoaPods repository 中文 English 在终端中运行以下命令: Run the following command in the terminal:
pod search CYLTabBarController
中文 English 注意:该命令搜索的是本机缓存,并不会联网查询。 Note: this command searches the local cache and does not query the network.
中文 English 如果没有找到库或版本不是最新,请更新本地源: If the library is missing or outdated, update the local repository:
[CN]3. 使用 CocoaPods 导入
[EN]3. Integrate with CocoaPods 中文 English 进入工程目录并初始化 Podfile: Open your project directory and initialize a Podfile:
中文 English 如果尚未安装 CocoaPods,也可以运行: If CocoaPods is not installed, run:
中文 English 打开 Podfile,在目标 target 中加入以下内容。版本号请以 podspec 为准。 Open the Podfile and add the following line to your target. Check the podspec for the latest version.
中文 English 在文件 Podfile 中加入以下内容: Add the following content to the Podfile:
pod 'CYLTabBarController', '~> 1.24.0'
中文 English 安装依赖: Install the dependency:
中文 English 如果不希望更新 spec 仓库,可使用: To avoid updating the spec repository, use:
# 禁止升级 CocoaPods 的 spec 仓库,否则会卡在 Analyzing dependencies,非常慢
pod update --verbose --no-repo-update
中文 English 如果提示找不到库,请移除 --no-repo-update。 If the library cannot be found, remove --no-repo-update.
中文 English 安装完成后,CocoaPods 会在工程根目录生成 .xcworkspace 文件。请使用该文件打开工程,而不是 .xcodeproj。 After installation, CocoaPods creates an .xcworkspace file in the project root. Open the project with this file instead of the .xcodeproj.
[CN]CocoaPods 使用说明
[EN]CocoaPods usage notes
[CN]指定 CYLTabBarController 版本
[EN]Pinning the CYLTabBarController version 中文 English 可以使用以下版本约束: You can use the following version constraints:
中文 English >= 1.n.X 会根据您本地的 CocoaPods 源列表,导入不低于 1.(n+1).X 版本的 CYLTabBarController。Based on your local CocoaPods sources, imports a CYLTabBarController version no lower than 1.(n+1).X.
中文 English ~> 1.n.X 会根据您本地的 CocoaPods 源列表,介于 1.n.X~1.(n+1).0 之前版本的 CYLTabBarController。Based on your local CocoaPods sources, imports a CYLTabBarController version from 1.n.X up to but not including 1.(n+1).0.
中文 English 建议锁定版本,便于团队协作。 Pinning a version is recommended for consistent team builds.
中文 English (此处示例可能是旧版本,使用时请替换为最新版,最新版信息可以从这里获取:podspec 。) This example may use an older version. Replace it with the latest version when needed; the latest version is available in the podspec .
pod 'CYLTabBarController', '~> 1.24.0'
[CN]升级本地 CocoaPods 源
[EN]Update the local CocoaPods repository 中文 English CocoaPods 会在本地缓存源服务器上的版本。如果搜索不到最新版本,请运行: CocoaPods caches versions locally. Run the following command when the latest version is unavailable:
[CN]升级工程中的 CYLTabBarController 版本
[EN]Upgrade CYLTabBarController in the project 中文 English 修改 Podfile 中的版本后运行: After changing the version in the Podfile, run:
[CN]清除 CocoaPods 本地缓存
[EN]Clear the CocoaPods cache 中文 English 如果下载文件损坏,可以删除 ~/Library/Caches/CocoaPods/Pods/Release 后重新导入。 If downloaded files are corrupted, remove ~/Library/Caches/CocoaPods/Pods/Release and integrate again.
[CN]查看当前使用的版本
[EN]Check the installed version 中文 English 在 Podfile.lock 中可以查看项目使用的版本。 The installed version is recorded in Podfile.lock.
[CN]使用 Carthage 导入 CYLTabBarController(可选)
[EN]Import CYLTabBarController with Carthage (optional) 中文 English 除了 CocoaPods 和 Swift Package Manager,也可以通过 Carthage 集成本库。在 Cartfile 中添加: In addition to CocoaPods and Swift Package Manager, you can integrate the library with Carthage . Add the following to Cartfile:
github "ChenYilong/CYLTabBarController"
carthage update --use-xcframeworks
中文 English 构建完成后,将生成的 CYLTabBarController.xcframework 拖入工程,并在 "Frameworks, Libraries, and Embedded Content" 中设置为 Embed & Sign。 After the build completes, drag CYLTabBarController.xcframework into the project and set it to Embed & Sign under "Frameworks, Libraries, and Embedded Content".
中文 English 说明:Carthage 构建的是不含 Lottie 动画相关文件(LottieSwift 目录)的核心功能集,与 CocoaPods 的 Core子规范(subspec)范围一致。 Note: Carthage builds the core feature set without the Lottie animation files in the LottieSwift directory, matching the scope of the CocoaPods Core subspec.
[CN]第二步:设置 CYLTabBarController 的两个数组
[EN]Step 2: Configure the view controller and tab bar item attribute arrays //MainTabBarController
@interface MainTabBarController : CYLTabBarController
@end
- (instancetype)init {
if (!(self = [super init])) {
return nil;
}
/**
* 以下两行代码目的在于手动设置让TabBarItem只显示图标,不显示文字,并让图标垂直居中。
* 等效于在 `-tabBarItemsAttributesForController` 方法中不传 `CYLTabBarItemTitle` 字段。
* 更推荐后一种做法。
*/
UIEdgeInsets imageInsets = UIEdgeInsetsZero;//UIEdgeInsetsMake(4.5, 0, -4.5, 0);
UIOffset titlePositionAdjustment = UIOffsetMake(0, -3.5);
CYLTabBarController *tabBarController = [CYLTabBarController tabBarControllerWithViewControllers:self.viewControllers
tabBarItemsAttributes:self.tabBarItemsAttributesForController
imageInsets:imageInsets
titlePositionAdjustment:titlePositionAdjustment
context:nil
];
[self customizeTabBarAppearance:tabBarController];
self.navigationController.navigationBar.hidden = YES;
return (self = (MainTabBarController *)tabBarController);
}
- (NSArray *)viewControllers {
CYLHomeViewController *firstViewController = [[CYLHomeViewController alloc] init];
UIViewController *firstNavigationController = [[CYLBaseNavigationController alloc]
initWithRootViewController:firstViewController];
[firstViewController cyl_setHideNavigationBarSeparator:YES];
CYLSameCityViewController *secondViewController = [[CYLSameCityViewController alloc] init];
UIViewController *secondNavigationController = [[CYLBaseNavigationController alloc]
initWithRootViewController:secondViewController];
[secondViewController cyl_setHideNavigationBarSeparator:YES];
NSArray *viewControllers = @[
firstNavigationController,
secondNavigationController,
];
return viewControllers;
}
- (NSArray *)tabBarItemsAttributesForController {
NSDictionary *firstTabBarItemsAttributes = @{
CYLTabBarItemTitle : @"首页",
CYLTabBarItemImage : self.darkMode ? @"home_highlight" : @"home_normal", /* NSString and UIImage are supported*/
CYLTabBarItemSelectedImage : @"home_highlight", /* NSString and UIImage are supported*/
};
NSDictionary *secondTabBarItemsAttributes = @{
CYLTabBarItemTitle : @"同城",
CYLTabBarItemImage : self.darkMode ? @"fishpond_highlight" : @"fishpond_normal",
CYLTabBarItemSelectedImage : @"fishpond_highlight",
};
NSArray *tabBarItemsAttributes = @[
firstTabBarItemsAttributes,
secondTabBarItemsAttributes,
];
return tabBarItemsAttributes;
}
中文 English 在这个字典中,CYLTabBarItemImage 和 CYLTabBarItemSelectedImage 支持 NSString、UIImage 两种格式。 The CYLTabBarItemImage and CYLTabBarItemSelectedImage values support both NSString and UIImage. 不设置 CYLTabBarItemTitle 时,只显示图标并自动居中。 Omit CYLTabBarItemTitle to display and center the icon only.
[CN]第三步:将 CYLTabBarController 设置为 window 的 RootViewController
[EN]Step 3: Set CYLTabBarController as the window's root view controller - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/* *省略部分: * */
[self.window setRootViewController:self.tabBarController];
/* *省略部分: * */
return YES;
}
中文 English 也可以将 CYLTabBarController 的子类设置为 RootViewController,或将其 NavigationViewController 设置为 RootViewController。 You can also use a CYLTabBarController subclass, or its NavigationViewController, as the root view controller. Demo 使用后者,便于动态更新。 The demo uses the latter so the hierarchy can be updated dynamically.
[CN]第四步(可选):创建自定义的不规则加号按钮
[EN]Step 4 (optional): Create a custom irregular plus button 中文 English 创建一个继承自 CYLPlusButton 的类,并按以下步骤配置: Create a CYLPlusButton subclass and follow these steps:
中文 English 实现 CYLPlusButtonSubclassing 协议。 Conform to CYLPlusButtonSubclassing.
中文 English 注册子类:调用 [YourClass registerPlusButton]。建议在 RootViewController 的 viewDidLoad 或 application:didFinishLaunchingWithOptions: 中注册。 Register the subclass with [YourClass registerPlusButton] from viewDidLoad or application:didFinishLaunchingWithOptions:.
中文 English 不要在子类的 +load 方法中注册,否则在 iOS 10 上可能发生崩溃。 Do not register it from +load, because this may crash on iOS 10.
+ (void)load {
[super registerPlusButton];
}
中文 English 协议提供以下可选方法: The protocol provides the following optional methods:
+ (NSUInteger)indexOfPlusButtonInTabBar;
+ (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight;
+ (UIViewController *)plusChildViewController;
+ (BOOL)shouldSelectPlusChildViewController;
中文 English 这些方法的作用如下: Their roles are described below.
+ (NSUInteger)indexOfPlusButtonInTabBar;
中文 English 用于自定义 PlusButton 的位置。未实现时默认居中;当 TabBarItem 数量为奇数时必须实现,否则会抛出异常。 Use this method to customize the PlusButton index. It defaults to the center, but must be implemented when the number of TabBarItems is odd.
中文 English 主要适用于如下情景: This is mainly useful in the following situations:
中文 English Airbnb app 效果 / Airbnb-style layout: Airbnb-style layout:
+ (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight;
中文 English 该方法用于调整自定义按钮中心点在 Y 轴上的位置,适用于按钮超出 TabBar 边界的场景。 Use this method to adjust the button center on the Y axis, especially when it extends beyond the TabBar. 返回值为按钮中心点 Y 坐标与 TabBar 高度的比值;不实现时使用自动布局。 The return value is the button center Y coordinate divided by the TabBar height. Automatic positioning is used when it is not implemented.
中文 English 内部实现时,会使用该返回值来设置 PlusButton 的 centerY 坐标,公式如下: PlusButtonCenterY = multiplierOfTabBarHeight * taBarHeight + constantOfPlusButtonCenterYOffset;
中文 English 当 constantOfPlusButtonCenterYOffset 为 0 且 multiplierOfTabBarHeight 为 0.5 时,PlusButton 居中;小于 0.5 时向上,大于 0.5 时向下。 With an offset of 0, a multiplier of 0.5 centers the PlusButton. Values below 0.5 move it upward; values above 0.5 move it downward.
+ (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight;
中文 English 参考 +multiplierOfTabBarHeight: 中的公式: PlusButtonCenterY = multiplierOfTabBarHeight * taBarHeight + constantOfPlusButtonCenterYOffset;
中文 English constantOfPlusButtonCenterYOffset 大于 0 时向下偏移,小于 0 时向上偏移。Positive values move the button downward; negative values move it upward.
中文 English 如果只实现该方法而未实现 +multiplierOfTabBarHeight:,偏移量会叠加到默认布局逻辑上。 If only this method is implemented, the offset is applied on top of the default layout.
中文 English 详见 Demo 中 CYLPlusButtonSubclass 的实现。 See CYLPlusButtonSubclass in the demo for a complete implementation.
+ (UIViewController *)plusChildViewController;
中文 English 另外,如果加号按钮超出了边界,一般需要手动调用如下代码取消 tabbar 顶部默认的阴影,可在 AppDelegate 类中调用: If the plus button extends beyond the bounds, you may need to remove the default tab bar top shadow by calling the following code from the AppDelegate:
//去除 TabBar 自带的顶部阴影
[[UITabBar appearance] setShadowImage:[[UIImage alloc] init]];
// iOS 10 and later: use -[CYLTabBarController hideTabBarShadowImageView].
// See the AppDelegate example.
[CN]调整 PlusButton 与 TabBarItem 的宽度
[EN]Customize the PlusButton and TabBarItem widths 中文 English CYLTabBarController 使用以下计算方式:CYLTabBarController uses the following formula:
TabBarItem 宽度 = ( TabBar 总宽度 - PlusButton 宽度 ) / (TabBarItem 个数)
中文 English 因此只需修改 PlusButton 的宽度即可改变各 TabBarItem 的宽度。 Change the PlusButton width to customize the width of the other TabBarItems.
中文 English 例如,在 Demo 的 CYLPlusButtonSubclass.m 中: For example, in CYLPlusButtonSubclass.m:
button.frame = CGRectMake(0.0, 0.0, 250, 100);
button.backgroundColor = [UIColor redColor];
中文 English 效果如下: The result is shown below:
中文 English 你也可以测试 CYLTabBarController 的以下特性: You can also test this feature:
中文 English 即使 PlusButton 超出 TabBar 区域,超出部分仍可响应点击事件。 The portion of PlusButton outside the TabBar bounds can still receive taps.
中文 English 你还可以在任意位置读取 CYLPlusButtonWidth,该 extern 定义在 CYLTabBarController.h 中。 The PlusButton width is also available through the CYLPlusButtonWidth extern declared in CYLTabBarController.h. 参考 +[CYLTabBarControllerConfig customizeTabBarAppearance:] 的用法。 See +[CYLTabBarControllerConfig customizeTabBarAppearance:] for an example.
[CN]补充说明
[EN]Additional notes
[CN]自定义 TabBar 样式
[EN]Customizing the TabBar appearance 中文 English 可以在 -application:didFinishLaunchingWithOptions: 中进一步自定义 TabBar 样式。 Customize the TabBar appearance from -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;
}
[CN]捕获 TabBar 点击事件
[EN]Handling TabBar selection events 中文 English 实现以下代理方法即可捕获点击事件。 Implement the following delegate methods to observe selections.
中文 English 下面的方法可以捕获 TabBar 上被点击的控件,包括 UITabBarButton、PlusButton 或其他 UIControl。 This method reports the selected control, including UITabBarButton, PlusButton, or any other UIControl. 如果 PlusButton 自身添加了点击事件,点击它时不会触发该代理方法。 It is not called for PlusButton when PlusButton has its own action.
//CYLTabBarController.h
@protocol CYLTabBarControllerDelegate <NSObject>
/*!
* @param tabBarController The tab bar controller containing viewController.
* @param control Selected UIControl in TabBar.
* @attention If PlusButton also add an action, then this delegate method will not be invoked when the PlusButton is selected.
*/
- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control;
@end
中文 English 下面的方法可以捕获跳转前的控制器和即将跳转到的目标控制器。 The following method receives the current and destination view controllers.
//UITabBarController.h
@protocol UITabBarControllerDelegate <NSObject>
@optional
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController NS_AVAILABLE_IOS(3_0);
@end
中文 English 注意:调用该方法时应始终调用 [[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController]; 以确保 PlusButton 的选中状态正确。 Always call the following method to keep the PlusButton selection state synchronized:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
[[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController];
return YES;
}
中文 English 完整用法请参考 Demo。 See the demo for a complete example.
中文 English 协议声明方式如下: Declare the protocols as follows:
@interface AppDelegate ()<UITabBarControllerDelegate, CYLTabBarControllerDelegate>
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//...
tabBarControllerConfig.tabBarController.delegate = self;
//...
return YES;
}
[CN]点击 TabBarButton 时添加动画
[EN]Adding animations when a TabBar button is tapped 中文 English Demo 效果: Demo preview:
中文 English 实现该代理方法即可获取选中的控件,并直接为其添加动画。 Implement this delegate method to access the selected control and animate it.
//CYLTabBarController.h
@protocol CYLTabBarControllerDelegate <NSObject>
/*!
* @param tabBarController The tab bar controller containing viewController.
* @param control Selected UIControl in TabBar.
*/
- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control;
@end
中文 English Demo 中的示例代码如下: The demo uses the following code:
中文 English 遵循协议: Conform to the protocols:
@interface AppDelegate ()<UITabBarControllerDelegate, CYLTabBarControllerDelegate>
@end
//AppDelegate.m
- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control {
UIView *animationView;
// If PlusButton has its own action, this delegate is not called for it.
if ([control isKindOfClass:[CYLExternPlusButton class]]) {
UIButton *button = CYLExternPlusButton;
animationView = button.imageView;
} else if ([control isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
for (UIView *subView in control.subviews) {
if ([subView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) {
animationView = subView;
}
}
}
if ([self cyl_tabBarController].selectedIndex % 2 == 0) {
[self addScaleAnimationOnView:animationView];
} else {
[self addRotateAnimationOnView:animationView];
}
}
// 缩放动画 / Scale animation
- (void)addScaleAnimationOnView:(UIView *)animationView {
// Customize the keyframe animation as needed.
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"transform.scale";
animation.values = @[@1.0,@1.3,@0.9,@1.15,@0.95,@1.02,@1.0];
animation.duration = 1;
animation.calculationMode = kCAAnimationCubic;
[animationView.layer addAnimation:animation forKey:nil];
}
// 旋转动画 / Rotation animation
- (void)addRotateAnimationOnView:(UIView *)animationView {
[UIView animateWithDuration:0.32 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
animationView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
} completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.70 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
animationView.layer.transform = CATransform3DMakeRotation(2 * M_PI, 0, 1, 0);
} completion:nil];
});
}
[CN]横竖屏适配
[EN]Supporting portrait and landscape orientations 中文 English 当 TabBar 中包含 PlusButton,且布局依赖 TabBarItem 宽度时,不建议使用系统的 UIDeviceOrientationDidChangeNotification。 When a PlusButton is present and your layout depends on TabBarItem width, do not rely on UIDeviceOrientationDidChangeNotification. 请使用 CYLTabBarItemWidthDidChangeNotification 更新布局,例如根据屏幕方向切换选中 TabBarItem 的背景图。 Use CYLTabBarItemWidthDidChangeNotification to update the layout, for example to switch the selected TabBarItem background image by orientation.
中文 English CYLTabBarController.h 提供了 CYLTabBarItemWidth extern 常量,并会在宽度变化时更新。CYLTabBarController.h exposes the CYLTabBarItemWidth extern, which is updated whenever the item width changes.
- (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]];
}
[CN]访问初始化好的 CYLTabBarController 对象
[EN]Accessing the initialized CYLTabBarController instance 中文 English 对于任意 NSObject 对象: For any NSObject:
中文 English CYLTabBarController.h 为 NSObject 提供了 -cyl_tabBarController 分类属性。CYLTabBarController.h adds -cyl_tabBarController to NSObject.因此可以在任意对象中用一行代码访问已初始化的 CYLTabBarController。 It provides one-line access to the initialized CYLTabBarController, similar to retrieving a shared instance.
中文 English 接口如下: The interface is:
// 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];
/*...*/
}
[CN]点击 PlusButton 跳转到指定 UIViewController
[EN]Navigating to a UIViewController by tapping the PlusButton 中文 English 通过协议方法即可实现该功能。 Use the protocol methods below to enable this behavior.
中文 English 实现后,点击 PlusButton 的效果与点击其他 TabBar 按钮一致,并跳转到指定的 UIViewController。 After implementation, tapping PlusButton behaves like tapping another TabBar button and navigates to the specified view controller.
中文 English 注意:必须同时实现 +indexOfPlusButtonInTabBar 指定 PlusButton 的位置。 You must also implement +indexOfPlusButtonInTabBar to define its position.
中文 English 协议示例: Protocol example:
#pragma mark - CYLPlusButtonSubclassing
+ (UIViewController *)plusChildViewController {
UIViewController *plusChildViewController = [[UIViewController alloc] init];
plusChildViewController.view.backgroundColor = [UIColor redColor];
plusChildViewController.navigationItem.title = @"PlusChildViewController";
UIViewController *plusChildNavigationController = [[UINavigationController alloc]
initWithRootViewController:plusChildViewController];
return plusChildNavigationController;
}
+ (NSUInteger)indexOfPlusButtonInTabBar {
return 2;
}
+ (BOOL)shouldSelectPlusChildViewController {
BOOL isSelected = CYLExternPlusButton.selected;
return YES;
}
+ (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight {
return 0.3;
}
+ (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight {
return (CYL_IS_IPHONE_X ? - 6 : 4);
}
//+ (NSString *)tabBarContext {
// return NSStringFromClass([self class]);
//}
中文 English 也可以通过下面的方法获取 PlusButton 的点击状态: Use the following method to inspect the PlusButton selection state:
+ (BOOL)shouldSelectPlusChildViewController;
+ (BOOL)shouldSelectPlusChildViewController {
BOOL isSelected = CYLExternPlusButton.selected;
if (isSelected) {
NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @"PlusButton is selected");
} else {
NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @"PlusButton is not selected");
}
return YES;
}
[CN]让 TabBarItem 仅显示图标并使图标垂直居中
[EN]Display only icons in TabBarItems and center them vertically 中文 English 要实现该效果,只需在 tabBarItemsAttributes 中省略 title。 To enable this behavior, omit title from tabBarItemsAttributes.
中文 English 例如,在 Demo 中注释掉下图红框部分: For example, comment out the highlighted code in the demo:
中文 English 这样即可实现 Airbnb app 风格: This produces an Airbnb-style layout:
中文 English 如需手动设置偏移量,可在 -setViewControllers: 前设置 imageInsets 和 titlePositionAdjustment。 To adjust the offset manually, set imageInsets and titlePositionAdjustment before -setViewControllers:.
中文 English 注意:这两个属性会应用于所有 TabBarItem,并优先于自动居中逻辑。 These properties apply to every TabBarItem and take precedence over the automatic centering logic.
中文 English Demo 中已提供完整示例。 See the demo for a complete example.
中文 English 要实现完整的 Airbnb app 效果,还需要设置 CYLTabBarController 的 tabBarHeight。 For the complete Airbnb-style layout, also set the tabBarHeight of CYLTabBarController. 可在 Demo 的 CYLTabBarControllerConfig.m 的 -customizeTabBarAppearance: 中设置。 Set it in -customizeTabBarAppearance: in the demo’s CYLTabBarControllerConfig.m.
中文 English 注:这里的“图标”属于系统私有类 UITabBarSwappableImageView,因此相关接口名称包含 SwappableImageView。 Note: the icon is backed by the private system class UITabBarSwappableImageView, which explains the SwappableImageView naming. 使用该特性需要将依赖更新到 1.5.5 或更高版本。 This feature requires version 1.5.5 or later.
[CN]多 TabBar 嵌套并指定 PlusButton 位置
[EN]Nesting multiple TabBars and specifying the PlusButton position 中文 English 旧版本可能不支持此功能,建议使用最新版本。 Older versions may not support this feature; use the latest release.
中文 English 效果图 / Preview: Preview:
中文 English 实现以下协议方法,为 PlusButton 指定 context: Implement the following protocol method to assign a context:
//CYLPlusButtonSubclassing
+ (NSString *)tabBarContext;
中文 English 当 PlusButton 的 context 与 TabBarController 的 context 匹配时,PlusButton 才会展示。 The PlusButton is shown when its context matches the TabBarController context. 如果两者都未设置 context,则默认视为匹配。 If neither value is set, they are considered equal by default.
中文 English 当前每次只展示一个 PlusButton,不限嵌套层级;如果匹配多个 TabBarController,则展示在第一个匹配的控制器上。 Only one PlusButton is displayed at a time, regardless of nesting depth. If multiple controllers match, it is shown on the first match.
[CN]在 Swift 项目中使用 CYLTabBarController
[EN]Using CYLTabBarController in a Swift project 中文 English 仓库提供了 Swift Demo,目录为 Example-Swift。 The repository includes a Swift demo in Example-Swift.
中文 English 在 Swift 项目中作为静态库使用: To use the library as a static library in a Swift project:
中文 English CocoaPods 1.5.0+ (with Xcode 9+): CocoaPods 1.5.0+ (with Xcode 9+):
platform :ios, '8.0'
# Uncomment the next line when you want all Pods as static framework
# use_modular_headers!
pod 'CYLTabBarController', '~> 1.29.0', :modular_headers => true
中文 English 作为动态库使用: To use it as a dynamic framework:
platform :ios, '8.0'
use_frameworks!
中文 English 注意:教程早期版本的示例缺少 PlusButton 尺寸设置,可能导致点击事件失效。当前教程已更新。 Note: an early version of the tutorial omitted the PlusButton size, which could disable taps. The tutorial has since been updated.
[CN]搭配 Storyboard 使用 CYLTabBarController
[EN]Using CYLTabBarController with Storyboard
[CN]源码实现原理
[EN]Implementation details
[CN]常见问题
[EN]FAQ
[CN]为什么放置 6 个 TabBarItem 会显示异常?
[EN]Why does placing six TabBarItems behave unexpectedly? 中文 English Apple 规定,一个 TabBar 最多显示 5 个 TabBarItem,第六个及之后的项目不会显示。 Apple allows a maximum of five TabBarItem instances in a TabBar; additional items are hidden.
中文 English Apple 检测的是 UITabBarItem 及其子类。由于 PlusButton 是 UIButton,它不计入这五个项目。 Because PlusButton is a UIButton, it is not counted as one of those five items.
中文 English 因此,一个 TabBar 最多可以放置 5 个 TabBarItem 和 1 个 PlusButton。 The practical limit is therefore five TabBarItems plus one PlusButton.
[CN]按钮响应区域发生偏移
[EN]The button hit area is offset 中文 English 我把 Demo 两侧的 item 各去掉一个后,按钮的响应区域变成了下图的样子: After removing one item from each side of the demo, the button hit area looked like this:
中文 English v1.5.5 已修复该问题,不会再出现点击区域无响应或响应区域偏移。 This was fixed in v1.5.5; the hit area should no longer be offset.
[CN]如何添加选中背景色?
[EN]How can I add a selected background color? 中文 English Demo 中已提供实现代码,详见 CYLTabBarControllerConfig 的以下方法: The demo includes an implementation in CYLTabBarControllerConfig:
/**
* 更多TabBar自定义设置:比如:tabBarItem 的选中和不选中文字和背景图片属性、tabbar 背景图片属性
*/
- (void)customizeTabBarAppearance:(CYLTabBarController *)tabBarController;
中文 English 效果如下: The result is shown below:
[CN]ViewController 标题与 TabBar 标题不一致
[EN]The ViewController title does not match the TabBar title 中文 English 当 ViewController 的 self.title 与 tabBarItemsAttributes 中的 title 不一致时,可能导致排序异常。 If self.title differs from the corresponding tabBarItemsAttributes title, the order may appear incorrect.
中文 English v1.0.7 已修复相关 bug,但仍建议不要使用 self.title 设置导航栏标题。 This bug was fixed in v1.0.7, but do not use self.title to set the navigation bar title.
中文 English 请使用 self.navigationItem.title = @"同城";: Use self.navigationItem.title = @"同城";:
中文 English self.title = @"同城"; 这种方式,如果和 tabBarItemsAttributes 中对应的 title 不一致的时候可能会导致如下现象(不算 bug,但看起来也很奇怪):If self.title = @"同城"; differs from the corresponding tabBarItemsAttributes title, the following strange-looking behavior may occur (this is not technically a bug):
中文 English 推荐规则如下: Recommended usage:
self.navigationItem.title = @"同城"; //✅sets navigation bar title.The right way to set the title of the navigation
self.tabBarItem.title = @"同城"; //❌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
[CN]调用 cyl_popSelectTabBarChildViewControllerAtIndex: 时出现黑边
[EN]Black borders appear when calling cyl_popSelectTabBarChildViewControllerAtIndex: 中文 English 这是早期 iOS 系统的问题,测试表明 iOS 9.3 已修复。 This was an issue on older iOS versions; testing shows that it was fixed in iOS 9.3. 在受影响的旧版本上,可以将根窗口背景色设置为白色: On affected older iOS versions, set the root window background color to white:
//#import "CYLTabBarController.h"
[[self cyl_tabBarController] rootWindow].backgroundColor = [UIColor whiteColor];
[CN]凸起的图标超出 49pt 后无法响应
[EN]A raised icon does not respond above 49pt 中文 English 库会自动处理,但只能保证 UIButton frame 内的区域可以响应。 The library handles this automatically, but only the UIButton frame is guaranteed to receive taps.
中文 English 请给 button 设置明显的背景色以确认实际 frame。红色区域可以响应,超出 button frame 的图片区域不能响应。 Use a visible background color to inspect the button frame. The button area receives taps; image pixels outside the frame do not.
中文 English 这是因为响应链中的 UIControl 可以响应点击,而 UIImage 不能。 This is because UIControl participates in hit testing, while UIImage does not.
[CN]为什么 iOS 10 会崩溃而 iOS 9 不会?
[EN]Why does it crash on iOS 10 but not iOS 9? 中文 English 注册 PlusButton 时,必须在 -application:didFinishLaunchingWithOptions: 中调用 [YourClass registerPlusButton]。 Register the PlusButton by calling [YourClass registerPlusButton] from -application:didFinishLaunchingWithOptions:.
中文 English 不要在子类的 +load 方法中调用,否则在 iOS 10 上可能崩溃。 Do not call it from the subclass +load method, as this may crash on iOS 10.
+ (void)load {
[super registerPlusButton];
}
[CN]PlusButton 选中后无法恢复为 normal
[EN]PlusButton remains selected after selecting another tab 中文 English 通常有两种原因: There are two common causes:
中文 English tabBar 设置了自定义 delegate,覆盖了默认状态切换逻辑。请在 delegate 中手动同步状态。A custom tabBar delegate may override the default selection handling. Synchronize the state manually:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
[[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController];
return YES;
}
中文 English PlusButton 添加了自定义点击事件或手势,与库内置逻辑冲突。请移除自定义 addTarget 或手势。 A custom action or gesture may conflict with the library. Remove the custom addTarget or gesture.
[CN]PlusButton 与其他 TabBarItem 的间距不均匀
[EN]The PlusButton is not evenly spaced 中文 English 将 Demo 中的: Replace this in the demo:
中文 English 改为: Replace it with:
button.frame = CGRectMake(0.0, 0.0, w, h);
中文 English 如果只放置一个相机图标,尺寸应以设计稿为准。 For a camera-only icon, use the size specified by your design.
中文 English 通常可以使用与其他 TabBarItem 相同的宽度: In most cases, use the same width as the other TabBarItems:
[UIScreen mainScreen].bounds.size.width / [CYLTabBarController allItemsInTabBarCount]
[CN]如何兼容 Lottie 动画?
[EN]How do I integrate Lottie animations?
[CN]Star 历史
[EN]Star history
中文 English 原创作品,版权声明:License MIT Original work. Copyright license: MIT.