CYLTabBarController单行代码 Lottie 动画 TabBar

联合创作 · 2023-09-26 15:37

CYLTabBarController 使用一行代码实现 Lottie 动画 TabBar,支持中间带 + 号的 TabBar 样式,自带红点角标,支持动态刷新。

集成后的效果

既支持默认样式 同时也支持创建自定义的形状不规则加号按钮
https://github.com/ChenYilong https://github.com/ChenYilong

支持横竖屏

与其他自定义TabBarController的区别

一行代码支持Lottie动画TabBar样式

低耦合,易删除

1、TabBar设置与业务完全分离,最低只需传两个数组即可完成主流App框架搭建。

2、 PlusButton 的所有设置都在单独的一个类( CYLPlusButton 的子类)中实现:删除该特定的类,就能完全将 PlusButton 从项目中删除掉。

TabBar 以及 TabBar 

 TabBarItem 均使用系统原生的控件

因为使用原生的控件,并非 UIButton  UIView 。好处如下:

  • 1. 无需反复调“间距位置等”来接近系统效果。
  • 2. 在push到下一页时 TabBar 的隐藏和显示之间的过渡效果跟系统一致
  • 3. 原生控件,所以可以使用诸多系统API,比如:可以使用 [UITabBar appearance];  [UITabBarItem appearance]; 设置样式。
自动监测是否需要添加“加号”按钮,并能自动设置位置

CYLTabBarController 既支持类似微信的“中规中矩”的 TabBarController 样式,并且默认就是微信这种样式,同时又支持类似“微博”或“淘宝闲鱼”这种具有不规则加号按钮的 TabBarController 

想支持这种样式,只需自定义一个加号按钮,CYLTabBarController 能检测到它的存在并自动将 tabBar 排序好,无需多余操作,并且也预留了一定接口来满足自定义需求。

“加号”按钮的样式、frame 均在自定义的类中独立实现,不会涉及 tabbar 相关设置。

支持动态更新

可动态删除PlusButton ,可以动态更新样式


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

红线内的区域均能响应tabbar相关的点击事件,


允许指定加号按钮位置

Airbnb-app效果:

支持让TabBarItem仅显示图标,并自动使图标垂直居中,支持自定义 TabBar 高度

效果可见 Airbnb-app 效果,或者下图

支持角标自定义View  

支持多 TabBar 嵌套,并指定 PlusButton 位置

 
支持 CocoaPods 容易集成
支持 Swift 项目导入 兼容
支持横竖屏  

项目结构

├── 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

  1. CocoaPods 安装

  如果您的机器上已经安装了 CocoaPods,直接进入下一步即可。

  如果您的网络已经翻墙,在终端中运行如下命令直接安装:

    sudo gem install cocoapods  

  如果您的网络不能翻墙,可以通过国内 Ruby China 的 RubyGems 镜像进行安装。

  在终端依次运行以下命令:

    gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/     sudo gem install cocoapods  

  1. 查询 CocoaPods 源中的本库

  在终端中运行以下命令:

    pod search CYLTabBarController  

   这里注意,这个命令搜索的是本机上的最新版本,并没有联网查询。如果运行以上命令,没有搜到或者搜不到最新版本,您可以运行以下命令,更新一下您本地的 CocoaPods 源列表。

    pod repo update  

  1. 使用 CocoaPods 导入

  打开终端,进入到您的工程目录,执行以下命令,会自动生成一个 Podfile 文件。

    pod init  

  然后使用 CocoaPods 进行安装。如果尚未安装 CocoaPods,运行以下命令进行安装:

gem install cocoapods

  打开 Podfile,在您项目的 target 下加入以下内容。(此处示例可能是旧版本,使用时请替换为最新版,最新版信息可以从这里获取:

  在文件 Podfile 中加入以下内容:

pod 'CYLTabBarController', '~> 1.24.0'

  然后在终端中运行以下命令:

pod install

  或者这个命令:

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

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

  完成后1.24.0,CocoaPods 会在您的工程根目录下生成一个 .xcworkspace 文件。您需要通过此文件打开您的工程,而不是之前的 .xcodeproj

CocoaPods 使用说明

指定 CYLTabBarController 版本

CocoaPods 中,有几种设置 CYLTabBarController 版本的方法。如:

>= 1.n.X 会根据您本地的 CocoaPods 源列表,导入不低于 1.(n+1).X 版本的 CYLTabBarController。

~> 1.n.X 会根据您本地的 CocoaPods 源列表,介于 1.n.X~1.(n+1).0 之前版本的 CYLTabBarController。

建议选择后者:锁定版本,便于团队开发。如:

(此处示例可能是旧版本,使用时请替换为最新版,最新版信息可以从这里获取:

pod 'CYLTabBarController', '~> 1.24.0'
  • 升级本地 CocoaPods 源

  `CocoaPods 有一个中心化的源,默认本地会缓存 CocoaPods 源服务器上的所有 CYLTabBarController 版本。

如果搜索的时候没有搜到或者搜不到最新版本,可以执行以下命令更新一下本地的缓存。

pod repo update
  • 升级工程的 CYLTabBarController 版本

更新您工程目录中 Podfile 指定的 CYLTabBarController 版本后,在终端中执行以下命令。

pod update
  • 清除 Cocoapods 本地缓存

特殊情况下,由于网络或者别的原因,通过 CocoaPods 下载的文件可能会有问题。

这时候您可以删除 CocoaPods 的缓存(~/Library/Caches/CocoaPods/Pods/Release 目录),再次导入即可。

  • 查看当前使用的 CYLTabBarController 版本

您可以在 Podfile.lock 文件中看到您工程中使用的 CYLTabBarController 版本。

关于 CocoaPods 的更多内容,您可以参考 CocoaPods 文档

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

//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;
}

在这个字典中,CYLTabBarItemImage  CYLTabBarItemSelectedImage 支持 NSStringUIImage 两种格式。CYLTabBarItemTitle 不设置将只展示图标,并会对布局作出居中处理。

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

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

或者将 CYLTabBarController 的子类设为 RootViewCOntroller ,也可以将CYLTabBarController子类的 NavigationViewController 作为 RootViewCOntroller,方便动态更新,Demo 中就是采用后者。

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

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

  1. 实现 CYLPlusButtonSubclassing 协议

  2. 子类将自身类型进行注册:调用 [YourClass registerPlusButton],需要在 RootViewCOntroller 的 ViewDidLoad 中注册,也可以在 -application:didFinishLaunchingWithOptions: 方法里面操作。

这里注意,不建议在子类的 +load 方法中调用,比如像下面这样做,在 iOS10 系统上有 Crash 的风险:

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

协议提供了可选方法:

+ (NSUInteger)indexOfPlusButtonInTabBar;
+ (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight;
+ (UIViewController *)plusChildViewController;
+ (BOOL)shouldSelectPlusChildViewController;

作用分别是:

+ (NSUInteger)indexOfPlusButtonInTabBar;

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

主要适用于如下情景:

Airbnb-app效果:

+ (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight;

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

内部实现时,会使用该返回值来设置 PlusButton 的 centerY 坐标,公式如下:

PlusButtonCenterY = multiplierOfTabBarHeight * taBarHeight + constantOfPlusButtonCenterYOffset;

也就是说:如果 constantOfPlusButtonCenterYOffset 为0,同时 multiplierOfTabBarHeight 的值是0.5,表示 PlusButton 居中,小于0.5表示 PlusButton 偏上,大于0.5则表示偏下。

+ (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight;

参考 +multiplierOfTabBarHeight: 中的公式:

PlusButtonCenterY = multiplierOfTabBarHeight * taBarHeight + constantOfPlusButtonCenterYOffset;

也就是说: constantOfPlusButtonCenterYOffset 大于0会向下偏移,小于0会向上偏移。

注意:实现了该方法,但没有实现 +multiplierOfTabBarHeight: 方法,在这种情况下,会在预设逻辑的基础上进行偏移。

详见Demo中的 CYLPlusButtonSubclass 类的实现。

+ (UIViewController *)plusChildViewController;

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

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

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

// iOS10 后 需要使用 -[CYLTabBarController hideTabBarShadowImageView] 见 AppDelegate 类中的演示;

如何调整、自定义 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];

效果如下, 1.24.0

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

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

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

 

浏览 9
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报