CYLTabBarController單行代碼 Lottie 動(dòng)畫(huà) TabBar
CYLTabBarController 使用一行代碼實(shí)現(xiàn) Lottie 動(dòng)畫(huà) TabBar,支持中間帶 + 號(hào)的 TabBar 樣式,自帶紅點(diǎn)角標(biāo),支持動(dòng)態(tài)刷新。
集成后的效果
| 既支持默認(rèn)樣式 | 同時(shí)也支持創(chuàng)建自定義的形狀不規(guī)則加號(hào)按鈕 |
|---|---|
支持橫豎屏
與其他自定義TabBarController的區(qū)別
| 一行代碼支持Lottie動(dòng)畫(huà)TabBar樣式 |
|
| 低耦合,易刪除 | 1、TabBar設(shè)置與業(yè)務(wù)完全分離,最低只需傳兩個(gè)數(shù)組即可完成主流App框架搭建。 2、 PlusButton 的所有設(shè)置都在單獨(dú)的一個(gè)類(lèi)( |
|
的 |
因?yàn)槭褂迷目丶⒎?span>
|
| 自動(dòng)監(jiān)測(cè)是否需要添加“加號(hào)”按鈕,并能自動(dòng)設(shè)置位置 | CYLTabBarController 既支持類(lèi)似微信的“中規(guī)中矩”的 想支持這種樣式,只需自定義一個(gè)加號(hào)按鈕,CYLTabBarController 能檢測(cè)到它的存在并自動(dòng)將 “加號(hào)”按鈕的樣式、frame 均在自定義的類(lèi)中獨(dú)立實(shí)現(xiàn),不會(huì)涉及 tabbar 相關(guān)設(shè)置。 |
| 支持動(dòng)態(tài)更新 | 可動(dòng)態(tài)刪除PlusButton ,可以動(dòng)態(tài)更新樣式
|
| 即使加號(hào)按鈕超出了tabbar的區(qū)域,超出部分依然能響應(yīng)點(diǎn)擊事件 | 紅線內(nèi)的區(qū)域均能響應(yīng)tabbar相關(guān)的點(diǎn)擊事件,
|
| 允許指定加號(hào)按鈕位置 | Airbnb-app效果: |
| 支持讓 |
效果可見(jiàn) Airbnb-app 效果,或者下圖 |
| 支持角標(biāo)自定義View | |
| 支持多 TabBar 嵌套,并指定 PlusButton 位置 |
|
| 支持 CocoaPods | 容易集成 |
| 支持 Swift 項(xiàng)目導(dǎo)入 | 兼容 |
| 支持橫豎屏 |
項(xiàng)目結(jié)構(gòu)
├── CYLTabBarController #核心庫(kù)文件夾,如果不使用 CocoaPods 集成,請(qǐng)直接將這個(gè)文件夾拖拽帶你的項(xiàng)目中
└── Example
└── Classes
├── Module #模塊類(lèi)文件夾
│ ├── Home
│ ├── Message
│ ├── Mine
│ └── SameCity
└── View #這里放著 CYLPlusButton 的子類(lèi) CYLPlusButtonSubclass,演示了如何創(chuàng)建自定義的形狀不規(guī)則加號(hào)按鈕
使用 CYLTabBarController
四步完成主流App框架搭建:
- 第一步:使用CocoaPods導(dǎo)入CYLTabBarController
- 第二步:設(shè)置CYLTabBarController的兩個(gè)數(shù)組:控制器數(shù)組和TabBar屬性數(shù)組
- 第三步:將CYLTabBarController設(shè)置為window的RootViewController
- 第四步(可選):創(chuàng)建自定義的形狀不規(guī)則加號(hào)按鈕
第一步:使用 CocoaPods 導(dǎo)入 CYLTabBarController
- CocoaPods 安裝
如果您的機(jī)器上已經(jīng)安裝了 CocoaPods,直接進(jìn)入下一步即可。
如果您的網(wǎng)絡(luò)已經(jīng)翻墻,在終端中運(yùn)行如下命令直接安裝:
sudo gem install cocoapods
如果您的網(wǎng)絡(luò)不能翻墻,可以通過(guò)國(guó)內(nèi) Ruby China 的 RubyGems 鏡像進(jìn)行安裝。
在終端依次運(yùn)行以下命令:
gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/ sudo gem install cocoapods
- 查詢 CocoaPods 源中的本庫(kù)
在終端中運(yùn)行以下命令:
pod search CYLTabBarController
這里注意,這個(gè)命令搜索的是本機(jī)上的最新版本,并沒(méi)有聯(lián)網(wǎng)查詢。如果運(yùn)行以上命令,沒(méi)有搜到或者搜不到最新版本,您可以運(yùn)行以下命令,更新一下您本地的 CocoaPods 源列表。
pod repo update
- 使用 CocoaPods 導(dǎo)入
打開(kāi)終端,進(jìn)入到您的工程目錄,執(zhí)行以下命令,會(huì)自動(dòng)生成一個(gè) Podfile 文件。
pod init
然后使用 CocoaPods 進(jìn)行安裝。如果尚未安裝 CocoaPods,運(yùn)行以下命令進(jìn)行安裝:
gem install cocoapods
打開(kāi) Podfile,在您項(xiàng)目的 target 下加入以下內(nèi)容。(此處示例可能是舊版本,使用時(shí)請(qǐng)?zhí)鎿Q為最新版,最新版信息可以從這里獲取:)
在文件 Podfile 中加入以下內(nèi)容:
pod 'CYLTabBarController', '~> 1.24.0'
然后在終端中運(yùn)行以下命令:
pod install
或者這個(gè)命令:
# 禁止升級(jí) CocoaPods 的 spec 倉(cāng)庫(kù),否則會(huì)卡在 Analyzing dependencies,非常慢
pod update --verbose --no-repo-update
如果提示找不到庫(kù),則可去掉 --no-repo-update。
完成后1.24.0,CocoaPods 會(huì)在您的工程根目錄下生成一個(gè) .xcworkspace 文件。您需要通過(guò)此文件打開(kāi)您的工程,而不是之前的 .xcodeproj。
CocoaPods 使用說(shuō)明
指定 CYLTabBarController 版本
CocoaPods 中,有幾種設(shè)置 CYLTabBarController 版本的方法。如:
>= 1.n.X 會(huì)根據(jù)您本地的 CocoaPods 源列表,導(dǎo)入不低于 1.(n+1).X 版本的 CYLTabBarController。
~> 1.n.X 會(huì)根據(jù)您本地的 CocoaPods 源列表,介于 1.n.X~1.(n+1).0 之前版本的 CYLTabBarController。
建議選擇后者:鎖定版本,便于團(tuán)隊(duì)開(kāi)發(fā)。如:
(此處示例可能是舊版本,使用時(shí)請(qǐng)?zhí)鎿Q為最新版,最新版信息可以從這里獲取:)
pod 'CYLTabBarController', '~> 1.24.0'
- 升級(jí)本地 CocoaPods 源
`CocoaPods 有一個(gè)中心化的源,默認(rèn)本地會(huì)緩存 CocoaPods 源服務(wù)器上的所有 CYLTabBarController 版本。
如果搜索的時(shí)候沒(méi)有搜到或者搜不到最新版本,可以執(zhí)行以下命令更新一下本地的緩存。
pod repo update
- 升級(jí)工程的 CYLTabBarController 版本
更新您工程目錄中 Podfile 指定的 CYLTabBarController 版本后,在終端中執(zhí)行以下命令。
pod update
- 清除 Cocoapods 本地緩存
特殊情況下,由于網(wǎng)絡(luò)或者別的原因,通過(guò) CocoaPods 下載的文件可能會(huì)有問(wèn)題。
這時(shí)候您可以刪除 CocoaPods 的緩存(~/Library/Caches/CocoaPods/Pods/Release 目錄),再次導(dǎo)入即可。
- 查看當(dāng)前使用的 CYLTabBarController 版本
您可以在 Podfile.lock 文件中看到您工程中使用的 CYLTabBarController 版本。
關(guān)于 CocoaPods 的更多內(nèi)容,您可以參考 CocoaPods 文檔。
第二步:設(shè)置 CYLTabBarController 的兩個(gè)數(shù)組:控制器數(shù)組和 TabBar 屬性數(shù)組
//MainTabBarController @interface MainTabBarController : CYLTabBarController @end - (instancetype)init { if (!(self = [super init])) { return nil; } /** * 以下兩行代碼目的在于手動(dòng)設(shè)置讓TabBarItem只顯示圖標(biāo),不顯示文字,并讓圖標(biāo)垂直居中。 * 等效于在 `-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 : @"首頁(yè)", CYLTabBarItemImage : self.darkMode ? @"home_highlight" : @"home_normal", /* NSString and UIImage are supported*/ CYLTabBarItemSelectedImage : @"home_highlight", /* NSString and UIImage are supported*/ }; NSDictionary *secondTabBarItemsAttributes = @{ CYLTabBarItemTitle : @"魚(yú)塘", CYLTabBarItemImage : self.darkMode ? @"fishpond_highlight" : @"fishpond_normal", CYLTabBarItemSelectedImage : @"fishpond_highlight", }; NSArray *tabBarItemsAttributes = @[ firstTabBarItemsAttributes, secondTabBarItemsAttributes, ]; return tabBarItemsAttributes; }
在這個(gè)字典中,CYLTabBarItemImage 和 CYLTabBarItemSelectedImage 支持 NSString、UIImage 兩種格式。CYLTabBarItemTitle 不設(shè)置將只展示圖標(biāo),并會(huì)對(duì)布局作出居中處理。
第三步:將 CYLTabBarController 設(shè)置為 window 的 RootViewController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { /* *省略部分: * */ [self.window setRootViewController:self.tabBarController]; /* *省略部分: * */ return YES; }
或者將 CYLTabBarController 的子類(lèi)設(shè)為 RootViewCOntroller ,也可以將CYLTabBarController子類(lèi)的 NavigationViewController 作為 RootViewCOntroller,方便動(dòng)態(tài)更新,Demo 中就是采用后者。
第四步(可選):創(chuàng)建自定義的形狀不規(guī)則加號(hào)按鈕
創(chuàng)建一個(gè)繼承于 CYLPlusButton 的類(lèi),要求和步驟:
-
實(shí)現(xiàn)
CYLPlusButtonSubclassing協(xié)議 -
子類(lèi)將自身類(lèi)型進(jìn)行注冊(cè):調(diào)用
[YourClass registerPlusButton],需要在 RootViewCOntroller 的 ViewDidLoad 中注冊(cè),也可以在-application:didFinishLaunchingWithOptions:方法里面操作。
這里注意,不建議在子類(lèi)的 +load 方法中調(diào)用,比如像下面這樣做,在 iOS10 系統(tǒng)上有 Crash 的風(fēng)險(xiǎn):
+ (void)load { [super registerPlusButton]; }
協(xié)議提供了可選方法:
+ (NSUInteger)indexOfPlusButtonInTabBar; + (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight; + (UIViewController *)plusChildViewController; + (BOOL)shouldSelectPlusChildViewController;
作用分別是:
+ (NSUInteger)indexOfPlusButtonInTabBar;
用來(lái)自定義加號(hào)按鈕的位置,如果不實(shí)現(xiàn)默認(rèn)居中,但是如果 tabbar 的個(gè)數(shù)是奇數(shù)則必須實(shí)現(xiàn)該方法,否則 CYLTabBarController 會(huì)拋出 exception 來(lái)進(jìn)行提示。
主要適用于如下情景:
Airbnb-app效果:
+ (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight;
該方法是為了調(diào)整自定義按鈕中心點(diǎn)Y軸方向的位置,建議在按鈕超出了 tabbar 的邊界時(shí)實(shí)現(xiàn)該方法。返回值是自定義按鈕中心點(diǎn)Y軸方向的坐標(biāo)除以 tabbar 的高度,如果不實(shí)現(xiàn),會(huì)自動(dòng)進(jìn)行比對(duì),預(yù)設(shè)一個(gè)較為合適的位置,如果實(shí)現(xiàn)了該方法,預(yù)設(shè)的邏輯將失效。
內(nèi)部實(shí)現(xiàn)時(shí),會(huì)使用該返回值來(lái)設(shè)置 PlusButton 的 centerY 坐標(biāo),公式如下:
PlusButtonCenterY = multiplierOfTabBarHeight * taBarHeight + constantOfPlusButtonCenterYOffset;
也就是說(shuō):如果 constantOfPlusButtonCenterYOffset 為0,同時(shí) multiplierOfTabBarHeight 的值是0.5,表示 PlusButton 居中,小于0.5表示 PlusButton 偏上,大于0.5則表示偏下。
+ (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight;
參考 +multiplierOfTabBarHeight: 中的公式:
PlusButtonCenterY = multiplierOfTabBarHeight * taBarHeight + constantOfPlusButtonCenterYOffset;
也就是說(shuō): constantOfPlusButtonCenterYOffset 大于0會(huì)向下偏移,小于0會(huì)向上偏移。
注意:實(shí)現(xiàn)了該方法,但沒(méi)有實(shí)現(xiàn) +multiplierOfTabBarHeight: 方法,在這種情況下,會(huì)在預(yù)設(shè)邏輯的基礎(chǔ)上進(jìn)行偏移。
詳見(jiàn)Demo中的 CYLPlusButtonSubclass 類(lèi)的實(shí)現(xiàn)。
+ (UIViewController *)plusChildViewController;
詳見(jiàn): 點(diǎn)擊 PlusButton 跳轉(zhuǎn)到指定 UIViewController
另外,如果加號(hào)按鈕超出了邊界,一般需要手動(dòng)調(diào)用如下代碼取消 tabbar 頂部默認(rèn)的陰影,可在 AppDelegate 類(lèi)中調(diào)用:
//去除 TabBar 自帶的頂部陰影 [[UITabBar appearance] setShadowImage:[[UIImage alloc] init]];
// iOS10 后 需要使用 -[CYLTabBarController hideTabBarShadowImageView] 見(jiàn) AppDelegate 類(lèi)中的演示;
如何調(diào)整、自定義 PlusButton 與其它 TabBarItem 的寬度?
CYLTabBarController 規(guī)定:
TabBarItem 寬度 = ( TabBar 總寬度 - PlusButton 寬度 ) / (TabBarItem 個(gè)數(shù))
所以想自定義寬度,只需要修改 PlusButton 的寬度即可。
比如你就可以在 Demo中的 CYLPlusButtonSubclass.m 類(lèi)里:
把
[button sizeToFit];
改為
button.frame = CGRectMake(0.0, 0.0, 250, 100); button.backgroundColor = [UIColor redColor];
效果如下, 1.24.0
同時(shí)你也可以順便測(cè)試下 CYLTabBarController 的這一個(gè)特性:
即使加號(hào)按鈕超出了tabbar的區(qū)域,超出部分依然能響應(yīng)點(diǎn)擊事件
并且你可以在項(xiàng)目中的任意位置讀取到 PlusButton 的寬度,借助 CYLTabBarController.h 定義的 CYLPlusButtonWidth 這個(gè)extern。可參考 +[CYLTabBarControllerConfig customizeTabBarAppearance:] 里的用法。
