- GitHub 源碼: CYLTabBarController
- Star: 6.1k
【中國特色 TabBar】一行代碼實現 Lottie 動畫 TabBar,支持中間帶 + 號的 TabBar 樣式,自帶紅點角標,支持動態刷新。【iOS13 & Dark Mode & iPhone XS MAX supported】。
前言
首先:不僅僅是一行代碼!
官方聲稱的 "一行代碼實現 Lottie 動畫 TabBar" 其實有虛晃一槍的嫌疑,讓你聽起來誤以為用一行代碼就可以實現淘寶「閑魚」那種既帶 ? 號按鈕又帶 Lottie 動畫的 TabBar 了。其實折騰下來還是要寫個幾百行代碼的。正確的描述應該是:集成 CYLTabBarController 之后,再導入所需的 JSON 文件(該文件用于描述 TabBar 的 Lottie 動畫),并添加一行代碼,即可讓 TabBar 實現 Lottie 動畫。
因此,所謂的 "一行代碼實現 Lottie 動畫”,其實就是配置方法里面再加一個 key 值為 CYLTabBarLottieURL
的屬性,它的值是一個 NSURL
鏈接,指向你項目中描述 Lottie 動畫的 JSON 文件。你還是需要自己提前準備好 Lottie 的 JSON 文件的,所以說,所謂的一行代碼就是,當涉及到 Lottie 動畫時,你給系統傳一個帶 Lottie 動畫的 URL 文件(既然“一行代碼”是這個意思的話,我是不是可以說一行代碼實現一個全套 Google 搜索引擎功能呢?打開一個 google.com 的 HTML 5 頁面不就實現了嘛)。
另外,一看見 CYLTabBarController 這個框架是國人寫的,而且 README 文檔是中文的,真的是喜極而泣??,讓我誤以為花個 5 分鐘便可以從入門到精通,最終折騰了好幾天,下載了好幾個 Demo 才算弄明白。
鑒于官方 README.md 文檔的“含糊不清”,與配套 Demo 寫法上也存在很大的出入,還是讓一開始初入了解該框架的同學造成了很大的困擾。
接下來,我會通過實現一個模仿「閑魚」TabBar 動畫的 Demo 來讓大家重新了解它。
開始使用
準備:新建 Xcode 項目
在 Xcode 11 環境下新建一個 Single View App 項目,打開這個新的項目,可以看到系統除了會自動生成 AppDelegate
文件外,還會自動生成一個名為 SceneDelegate
的類文件。
?? SceneDelegate
是 iOS 13 下的新特性,查看 WWDC 2019: Optimizing App Launch 可以知道這到底是啥,但是 CYLTabBarController 還未適配該特性(截止 1.28.3 版本),基于 SceneDelegate
集成該框架應用會崩潰!所以我們要先把 SceneDelegate
特性刪除才行。
步驟:
- 首先打開
Info.plist
文件,找到下面這兩個屬性并刪除。
- 刪除
SceneDelegate
類文件,其實可刪可不刪,但既然我們用不到就刪了吧。 - 修改
AppDelegate.h
文件,加上UIWindow
屬性。
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow * window;
@end
- 修改
AppDelegate.m
文件,設置UIWindow
設置主窗口,并刪除多余的 <UISceneSession> 代理協議。
#import "AppDelegate.h"
#import "ViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// 設置根視圖控制器
ViewController *controller = [[ViewController alloc] init];
// 窗口根視圖控制器
self.window.rootViewController = controller;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
// 下面多余的代碼請刪除
@end
運行項目,無報錯則繼續往下。
第一步:使用 CocoaPods 導入 CYLTabBarController
可以很良心的說,README.md 文檔中在 第一步使用 CocoaPods 導入 CYLTabBarController 一章算是描述地最詳盡的了,它居然還教你如何安裝 CocoaPods,堪比 CocoaPods 環境搭建教程了。
但是,有一點需要提醒的是,安裝 CocoaPods 請勿使用 sudo gem install cocoapods
這個命令,如果運行該命令提示存在權限問題:
# 錯誤示例
$ sudo gem install cocoapods
Password:
Fetching cocoapods-1.8.4.gem
Fetching cocoapods-core-1.8.4.gem
Successfully installed cocoapods-core-1.8.4
ERROR: While executing gem ... (Gem::FilePermissionError)
You don't have write permissions for the /usr/bin directory.
# Mac OS 系統升級之后,系統把 /usr/bin 目錄的寫入權限禁用了,因此我們需要指定安裝到別的目錄下。
# 正確示例,需要安裝 cocoapods 到指定目錄下
$ sudo gem install cocoapods -n /usr/local/bin
Successfully installed cocoapods-1.8.4
Parsing documentation for cocoapods-1.8.4
Installing ri documentation for cocoapods-1.8.4
Done installing documentation for cocoapods after 2 seconds
1 gem installed
另外,Podfile 示例文件如下:
# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'
target 'CYLTabBarControllerDemo' do
# Comment the next line if you don't want to use dynamic frameworks
# use_frameworks!
# Pods for CYLTabBarControllerDemo
pod 'CYLTabBarController', '~> 1.28.3' # 默認不依賴Lottie
pod 'CYLTabBarController/Lottie', '~> 1.28.1' # 依賴Lottie庫
pod 'ChameleonFramework' # 顏色框架
pod 'YYKit' # 會用到幾個輔助方法
end
第二步:新建 AppDelegate 分類文件,初始化并設置 CYLTabBarController
如果你查看 CYLTabBarController 框架的 README.md 文檔,作者會讓你把很多配置方法寫在 AppDelegate
這個類中。
但實際應用場景中,有很多配置方法都要寫在這個文件里面,比如日志框架的配置、推送通知框架、第三方支付回調配置...還有一大堆工具類配置。
所以我習慣上會把不同的配置文件單獨寫在各自的分類(Category)中。
具體原因可以去看看《Effective Objective-C 2.0 編寫高質量 iOS 與 OS X 代碼的 52 個有效方法 》一書中的第 24 條建議。
因此,我們需要新建一個 AppDelegate
分類文件,然后把所有與初始化 CYLTabBarController 框架相關的代碼都寫在 AppDelegate+CYLTabBar
文件里面,保持代碼整潔,方便修改。
-
新建一個
AppDelegate
分類文件。點擊 Xcode 導航欄 — File — New — File...— 選擇 iOS Source 列表下的「Objective-C File」,新建文件類型和文件名如下:
image 在 Assets.xcassets 資產庫中導入你所需要的圖片文件。
在分類中新建一個方法,用于配置主窗口:
#import "AppDelegate.h"
NS_ASSUME_NONNULL_BEGIN
/// 這是 AppDelegate 的分類,用于配置 CYLTabBarController
@interface AppDelegate (CYLTabBar)
/// 配置主窗口
- (void)hql_configureForTabBarController;
@end
NS_ASSUME_NONNULL_END
然后我們在 .m 文件中實現它,設置 CYLTabBarController
的兩個數組:控制器數組和配置 tabBar 外觀樣式的屬性數組:
@implementation AppDelegate (CYLTabBar)
#pragma mark - Public
- (void)hql_configureForTabBarController {
// 設置主窗口,并設置根視圖控制器
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
// 初始化 CYLTabBarController 對象
CYLTabBarController *tabBarController =
[CYLTabBarController tabBarControllerWithViewControllers:[self viewControllers]
tabBarItemsAttributes:[self tabBarItemsAttributes]];
// 設置遵守委托協議
tabBarController.delegate = self;
// 將 CYLTabBarController 設置為 window 的 RootViewController
self.window.rootViewController = tabBarController;
}
#pragma mark - Private
/// 控制器數組
- (NSArray *)viewControllers {
// 首頁
HomeViewController *homeVC = [[HomeViewController alloc] init];
homeVC.navigationItem.title = @"首頁";
CYLBaseNavigationController *homeNC = [[CYLBaseNavigationController alloc] initWithRootViewController:homeVC];
[homeNC cyl_setHideNavigationBarSeparator:YES];
// 同城
MyCityViewController *myCityVC = [[MyCityViewController alloc] init];
myCityVC.navigationItem.title = @"同城";
CYLBaseNavigationController *myCityNC = [[CYLBaseNavigationController alloc] initWithRootViewController:myCityVC];
[myCityNC cyl_setHideNavigationBarSeparator:YES];
// 消息
MessageViewController *messageVC = [[MessageViewController alloc] init];
messageVC.navigationItem.title = @"消息";
CYLBaseNavigationController *messageNC = [[CYLBaseNavigationController alloc] initWithRootViewController:messageVC];
[messageNC cyl_setHideNavigationBarSeparator:YES];
// 我的
AccountViewController *accountVC = [[AccountViewController alloc] init];
accountVC.navigationItem.title = @"我的";
CYLBaseNavigationController *accountNC = [[CYLBaseNavigationController alloc] initWithRootViewController:accountVC];
[accountNC cyl_setHideNavigationBarSeparator:YES];
NSArray *viewControllersArray = @[homeNC, myCityNC, messageNC, accountNC];
return viewControllersArray;
}
/// tabBar 屬性數組
- (NSArray *)tabBarItemsAttributes {
NSDictionary *homeTabBarItemsAttributes = @{
CYLTabBarItemTitle: @"首頁",
CYLTabBarItemImage: @"home_normal",
CYLTabBarItemSelectedImage: @"home_highlight",
};
NSDictionary *myCityTabBarItemsAttributes = @{
CYLTabBarItemTitle: @"同城",
CYLTabBarItemImage: @"mycity_normal",
CYLTabBarItemSelectedImage: @"mycity_highlight",
};
NSDictionary *messageTabBarItemsAttributes = @{
CYLTabBarItemTitle: @"消息",
CYLTabBarItemImage: @"message_normal",
CYLTabBarItemSelectedImage: @"message_highlight",
};
NSDictionary *accountTabBarItemsAttributes = @{
CYLTabBarItemTitle: @"我的",
CYLTabBarItemImage: @"account_normal",
CYLTabBarItemSelectedImage: @"account_highlight",
};
NSArray *tabBarItemsAttributes = @[
homeTabBarItemsAttributes,
myCityTabBarItemsAttributes,
messageTabBarItemsAttributes,
accountTabBarItemsAttributes
];
return tabBarItemsAttributes;
}
@end
- 最后,我們回到
AppDelegate.m
文件,導入上一步新建的分類頭文件 :
#import "AppDelegate+CYLTabBar.h"
- 然后一行代碼調用配置主窗口的方法:
#import "AppDelegate.h"
#import "AppDelegate+CYLTabBar.h" // 導入的分類文件
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 調用分類文件中的配置主窗口方法:
[self hql_configureForTabBarController];
return YES;
}
@end
- 至此,常見的帶 4 個 TabBarItem 的應用框架就搭建好啦:
小結:將 CYLTabBarController
實例化為窗口的根視圖控制器即可。
第三步:添加不規則加號按鈕
創建一個繼承自 CYLPlusButton
的子類對象 CYLPlusButtonSubclass
。
CYLPlusButtonSubclass.h
聲明遵守 <CYLPlusButtonSubclassing>
協議
#import "CYLPlusButton.h"
NS_ASSUME_NONNULL_BEGIN
@interface CYLPlusButtonSubclass : CYLPlusButton <CYLPlusButtonSubclassing>
@end
NS_ASSUME_NONNULL_END
CYLPlusButtonSubclass.m
中實現創建按鈕的方法和遵守的協議方法
#import "CYLPlusButtonSubclass.h"
@implementation CYLPlusButtonSubclass
#pragma mark - Lifecycle
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.adjustsImageWhenHighlighted = NO;
}
return self;
}
//上下結構的 button
- (void)layoutSubviews {
[super layoutSubviews];
// 控件大小,間距大小
// 注意:一定要根據項目中的圖片去調整下面的0.7和0.9,Demo之所以這么設置,因為demo中的 plusButton 的 icon 不是正方形。
CGFloat const imageViewEdgeWidth = self.bounds.size.width * 0.7;
CGFloat const imageViewEdgeHeight = imageViewEdgeWidth;
CGFloat const centerOfView = self.bounds.size.width * 0.5;
CGFloat const labelLineHeight = self.titleLabel.font.lineHeight;
CGFloat const verticalMargin = (self.bounds.size.height - labelLineHeight - imageViewEdgeHeight) * 0.5;
// imageView 和 titleLabel 中心的 Y 值
CGFloat const centerOfImageView = verticalMargin + imageViewEdgeHeight * 0.5;
CGFloat const centerOfTitleLabel = imageViewEdgeHeight + verticalMargin * 2 + labelLineHeight * 0.5 - 1;
//imageView position 位置
self.imageView.bounds = CGRectMake(0, 0, imageViewEdgeWidth, imageViewEdgeHeight);
self.imageView.center = CGPointMake(centerOfView, centerOfImageView);
//title position 位置
self.titleLabel.bounds = CGRectMake(0, 0, self.bounds.size.width, labelLineHeight);
self.titleLabel.center = CGPointMake(centerOfView, centerOfTitleLabel);
}
#pragma mark - IBActions
- (void)clickPublish {
// 如果按鈕的作用是觸發點擊事件,則調用此方法
}
#pragma mark - CYLPlusButtonSubclassing
+ (id)plusButton {
CYLPlusButtonSubclass *button = [CYLPlusButtonSubclass buttonWithType:UIButtonTypeCustom];
// 圖片尺寸:56*56、67*66、49*48(凸出 15)
UIImage *normalButtonImage = [UIImage imageNamed:@"post_normal"];
UIImage *hlightButtonImage = [UIImage imageNamed:@"post_highlight"];
[button setImage:normalButtonImage forState:UIControlStateNormal];
[button setImage:hlightButtonImage forState:UIControlStateHighlighted];
[button setImage:hlightButtonImage forState:UIControlStateSelected];
// 設置背景圖片
// UIImage *normalButtonBackImage = [UIImage imageNamed:@"tabBar_post_back"];
// [button setBackgroundImage:normalButtonBackImage forState:UIControlStateNormal];
// [button setBackgroundImage:normalButtonBackImage forState:UIControlStateSelected];
// 按鈕圖片距離上邊距增加 5,即向下偏移,按鈕圖片距離下邊距減少 5,即向下偏移。
//button.imageEdgeInsets = UIEdgeInsetsMake(5, 0, -5, 0);
[button setTitle:@"發布" forState:UIControlStateNormal];
[button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:10 weight:UIFontWeightBold];
[button sizeToFit]; // or set frame in this way `button.frame = CGRectMake(0.0, 0.0, 250, 100);`
//自定義寬度
button.frame = CGRectMake(0.0, 0.0, 59, 59);
// button.backgroundColor = [UIColor redColor];
// if you use `+plusChildViewController` , do not addTarget to plusButton.
// [button addTarget:button action:@selector(clickPublish) forControlEvents:UIControlEventTouchUpInside];
return button;
}
// 用來自定義加號按鈕的位置,如果不實現默認居中。
+ (NSUInteger)indexOfPlusButtonInTabBar {
return 2;
}
// 實現該方法后,能讓 PlusButton 的點擊效果與跟點擊其他 TabBar 按鈕效果一樣,跳轉到該方法指定的 UIViewController
+ (UIViewController *)plusChildViewController {
UIViewController *v = [[UIViewController alloc] init];
return v;
}
// 該方法是為了調整 PlusButton 中心點Y軸方向的位置,建議在按鈕超出了 tabbar 的邊界時實現該方法。
// 返回值是自定義按鈕中心點 Y 軸方向的坐標除以 tabbar 的高度,小于 0.5 表示 PlusButton 偏上,大于 0.5 則表示偏下。
// PlusButtonCenterY = multiplierOfTabBarHeight * tabBarHeight + constantOfPlusButtonCenterYOffset;
+ (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight {
return 0.3;
}
// constantOfPlusButtonCenterYOffset 大于 0 會向下偏移,小于 0 會向上偏移。
+ (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight {
return (CYL_IS_IPHONE_X ? - 6 : 4);
}
@end
在 AppDelegate+CYLTabBar.m
中注冊該按鈕
在初始化 CYLTabBarController
對象步驟之前注冊按鈕:
- (void)hql_configureForTabBarController {
// 設置主窗口,并設置根視圖控制器
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
// ?????? 注冊加號按鈕
[CYLPlusButtonSubclass registerPlusButton];
// 初始化 CYLTabBarController 對象
CYLTabBarController *tabBarController =
[CYLTabBarController tabBarControllerWithViewControllers:[self viewControllers]
tabBarItemsAttributes:[self tabBarItemsAttributes]];
// 設置遵守委托協議
tabBarController.delegate = self;
self.window.rootViewController = tabBarController;
}
自此,加號按鈕也添加完成啦。
第四步:設置自定義 TabBar 樣式
自定義 TabBar 字體、背景、陰影。
在 AppDelegate+CYLTabBar.m
文件中新增一個方法,用于設置 TabBar 樣式:
/// 自定義 TabBar 字體、背景、陰影
- (void)customizeTabBarInterface {
// 設置文字屬性
if (@available(iOS 10.0, *)) {
[self cyl_tabBarController].tabBar.unselectedItemTintColor = [UIColor cyl_systemGrayColor];
[self cyl_tabBarController].tabBar.tintColor = [UIColor cyl_labelColor];
} else {
UITabBarItem *tabBar = [UITabBarItem appearance];
// 普通狀態下的文字屬性
[tabBar setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor cyl_systemGrayColor]}
forState:UIControlStateNormal];
// 選中狀態下的文字屬性
[tabBar setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor cyl_labelColor]}
forState:UIControlStateSelected];
}
// 設置 TabBar 背景顏色:白色
// ??[UIImage imageWithColor] 表示根據指定顏色生成圖片,該方法來自 <YYKit> 框架
[[UITabBar appearance] setBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor]]];
// 去除 TabBar 自帶的頂部陰影
[[self cyl_tabBarController] hideTabBarShadowImageView];
// 設置 TabBar 陰影,無效
// [[UITabBar appearance] setShadowImage:[UIImage imageNamed:@"tabBar_background_shadow"]];
// 設置 TabBar 陰影
CYLTabBarController *tabBarController = [self cyl_tabBarController];
tabBarController.tabBar.layer.shadowColor = [UIColor blackColor].CGColor;
tabBarController.tabBar.layer.shadowRadius = 15.0;
tabBarController.tabBar.layer.shadowOpacity = 0.2;
tabBarController.tabBar.layer.shadowOffset = CGSizeMake(0, 3);
tabBarController.tabBar.layer.masksToBounds = NO;
tabBarController.tabBar.clipsToBounds = NO;
}
然后在該文件的配置方法中調用:
- (void)hql_configureForTabBarController {
// 設置主窗口,并設置根視圖控制器
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
// 注冊加號按鈕
[CYLPlusButtonSubclass registerPlusButton];
// 初始化 CYLTabBarController 對象
CYLTabBarController *tabBarController =
[CYLTabBarController tabBarControllerWithViewControllers:[self viewControllers]
tabBarItemsAttributes:[self tabBarItemsAttributes]];
// 設置遵守委托協議
tabBarController.delegate = self;
self.window.rootViewController = tabBarController;
// ?????? 自定義 TabBar 字體、背景、陰影
[self customizeTabBarInterface];
}
另外,不規則加號按鈕的背景圖片需要在 CYLPlusButtonSubclass.m
文件的 + (id)plusButton
中設置:
// 設置背景圖片
UIImage *normalButtonBackImage = [UIImage imageNamed:@"tabBar_post_back"];
[button setBackgroundImage:normalButtonBackImage forState:UIControlStateNormal];
[button setBackgroundImage:normalButtonBackImage forState:UIControlStateSelected];
下面是自定義后的 TabBar 樣式示例:
第五步:添加點擊旋轉動畫
當點擊 TabBarItem 時,為它設置旋轉動畫,需要讓 AppDelegate 遵守 <CYLTabBarControllerDelegate, UITabBarControllerDelegate>
委托協議,以監聽點擊觸發事件:
// ?????? 聲明遵守委托協議
@interface AppDelegate () <CYLTabBarControllerDelegate, UITabBarControllerDelegate>
@end
@implementation AppDelegate (CYLTabBar)
- (void)hql_configureForTabBarController {
// 省略...
// 初始化 CYLTabBarController 對象
CYLTabBarController *tabBarController =
[CYLTabBarController tabBarControllerWithViewControllers:[self viewControllers]
tabBarItemsAttributes:[self tabBarItemsAttributes]];
// ?????? 設置讓 AppDelegate 遵守委托協議
tabBarController.delegate = self;
self.window.rootViewController = tabBarController;
}
接下來是讓 AppDelegate 實現委托協議方法,點擊 TabBarItem 時觸發旋轉動畫,點不規則加號按鈕時觸發放大動畫:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
// 確保 PlusButton 的選中狀態
[[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController];
return YES;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control {
UIView *animationView;
NSLog(@"??\n 類名與方法名:%@,\n 第 %@ 行,\n description : %@,\n tabBarChildViewControllerIndex: %@, tabBarItemVisibleIndex : %@", @(__PRETTY_FUNCTION__), @(__LINE__), control, @(control.cyl_tabBarChildViewControllerIndex), @(control.cyl_tabBarItemVisibleIndex));
// 即使 PlusButton 也添加了點擊事件,點擊 PlusButton 后也會觸發該代理方法。
if ([control cyl_isPlusButton]) {
UIButton *button = CYLExternPlusButton;
animationView = button.imageView;
// 為加號按鈕添加「縮放動畫」
[self addScaleAnimationOnView:animationView repeatCount:1];
} else if ([control isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
for (UIView *subView in control.subviews) {
if ([subView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) {
animationView = subView;
// 為其他按鈕添加「旋轉動畫」
[self addRotateAnimationOnView:animationView];
}
}
}
}
/// 縮放動畫
- (void)addScaleAnimationOnView:(UIView *)animationView repeatCount:(float)repeatCount {
//需要實現的幀動畫,這里根據需求自定義
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 = 0.5;
animation.repeatCount = repeatCount;
animation.calculationMode = kCAAnimationCubic;
[animationView.layer addAnimation:animation forKey:nil];
}
/// 旋轉動畫
- (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];
});
}
實現效果:
第六步:添加 Lottie 動畫
參考:https://github.com/ChenYilong/CYLTabBarController/issues/341
首先,為方便演示,我們從官方 Demo 中獲取 Lottie 動畫的 JSON 文件和相關資源文件。
然后,修改配置 tabBar 屬性數組的方法 - (NSArray *)tabBarItemsAttributes
,把 Lottie 文件的 URL 路徑加上:
/*
* tabBar 屬性數組,帶 Loggie 動畫
* 參考:<https://github.com/ChenYilong/CYLTabBarController/issues/341>
*
* 與上面的配置相比,需要再多設置兩個屬性:
* CYLTabBarLottieURL: 傳入 lottie 動畫 JSON 文件所在路徑
* CYLTabBarLottieSize: LottieView 大小,選填
*
*/
- (NSArray *)tabBarItemsAttributes {
NSDictionary *homeTabBarItemsAttributes = @{
CYLTabBarItemTitle: @"首頁",
CYLTabBarLottieURL : [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"tab_home_animate" ofType:@"json"]],
CYLTabBarLottieSize: [NSValue valueWithCGSize:CGSizeMake(33, 33)],
};
NSDictionary *myCityTabBarItemsAttributes = @{
CYLTabBarItemTitle: @"同城",
CYLTabBarLottieURL : [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"tab_search_animate" ofType:@"json"]],
CYLTabBarLottieSize: [NSValue valueWithCGSize:CGSizeMake(33, 33)],
};
NSDictionary *messageTabBarItemsAttributes = @{
CYLTabBarItemTitle: @"消息",
CYLTabBarLottieURL : [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"tab_message_animate" ofType:@"json"]],
CYLTabBarLottieSize: [NSValue valueWithCGSize:CGSizeMake(33, 33)],
};
NSDictionary *accountTabBarItemsAttributes = @{
CYLTabBarItemTitle: @"我的",
CYLTabBarLottieURL : [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"tab_me_animate" ofType:@"json"]],
CYLTabBarLottieSize: [NSValue valueWithCGSize:CGSizeMake(33, 33)],
};
NSArray *tabBarItemsAttributes = @[
homeTabBarItemsAttributes,
myCityTabBarItemsAttributes,
messageTabBarItemsAttributes,
accountTabBarItemsAttributes
];
return tabBarItemsAttributes;
}
自此,我們通過 CYLTabBarController 框架實現了一個仿「閑魚」TabBar 動畫的應用。
Demo:HQLTableViewDemo