版本
Xcode 10.2
iPhone 6s (iOS12.4)
目录
- 版本
- 继承关系
- 简介
- 创建
- 方法属性
- UITabBarItem
- UIBarItem
继承关系
UITabBarController : UIViewController : UIResponder : NSObject
简介
A container view controller that manages a radio-style selection interface, where the selection determines which child view controller to display.
UITabBarController属于视图容器控制器, 管理着一个平行选择界面, 并显示其中一个选定的子视图控制器.
标签栏界面位于窗口底部, 栏中有很多选项 (Item),用于选择不同的模式以及显示该模式的视图。每个Item都与自定义视图控制器相关联, 当用户选择某个Item时,栏中该Item变成选中状态, 显示内容则变成Item所对应的视图控制器的view.
苹果自家闹钟App就是使用标签栏结构:
结构
我们还是从结构开始讲起. 先来看看这张熟悉的结构图:
在上一章UINavigationController中就出现过这张图, 可以看到, UITabBarController其实和UINavigationController是很相似的. 都是用来管理多个UIViewController的显示, 只不过UINavigationController的导航栏显示在窗口顶部, 而UITabBarController的标签栏显示在窗口的底部, 中间内容则是用于显示当前选中的视图控制器的view.
结构2.0
好像从上图中还看不出多少内容, 不如来看看我的DIY版本:
结构中, UITabBarController管理四个VC, 窗口底部有个UITabBar, 用于存放四个不同的UITabBarItem. 我们可以改变标签栏UITabBar的属性, 比如背景颜色, 背景图片, Item宽度等等. 每个UITabBarItem对应一个VC, 也是VC的一个属性(UITabBarControllerItem扩展). UITabBarItem继承自UIBarItem, 后文再介绍.
什么时候使用UITabBarController
当要显示的多个内容处于平级的时候, 建议使用UITabBarController.
创建
对于这种结构感比较强的界面设计, 当然首选storyboard了.
- 拖入一个tab bar controller, 设为is initial view controller
- 拖入几个view controller, 从tab bar controller分别引线至view controller, 选择view controllers, 生成segue线.
- 如果不用自定义导航栏, 则tab bar controller就不要去动了.
- 选中每个VC底部的tab bar item, 在右边栏修改属性的地方, 填写Bar Item里面的Image(未选中状态的图标), 以及Tab Bar Item里面的Selected Image (选中状态的图标). 注意: 如果不设置Image, 光填Selected Image是没有用的.
- 事先准备的图标image, 渲染模式应设置为UIImageRenderingModeAlwaysOriginal (Assets.xcassets选中图片, 右边属性栏中Render As选择Original Image), 图片大小准备两种分辨率: 60x60 (@2x), 90x90 (@3x). 如果有疑惑继续往下看.
- 补充一点, UITabBarItem中image大小对应图像中不透明区域 (alpha通道大于某个值) . 例如, 一个PNG图片, 画布大小为80x80, 不透明区域为50x50, 则在UITabBarItem中只显示50x50部分铺满image.
UITabBarItem图标颜色改变问题
一般设置image后, 可能会得到如下效果:
看看Apple官方文档:
By default, unselected and selected images are automatically created from the alpha values in the source images. To prevent system coloring, provide images with UIImageRenderingModeAlwaysOriginal.
默认情况下,将根据源图像中的Alpha值自动创建unselected和selected的image。 要防止系统着色,请使用UIImageRenderingModeAlwaysOriginal提供image。
原来是系统默认将我们的image变蓝了. 所以我们得把image的渲染模式 (Rendering Mode) 改成UIImageRenderingModeAlwaysOriginal.
- 法一: Assets.xcassets选中图片, 右边属性栏中Render As选择Original Image.
- 法二: [[UIImage imageNamed:@"XXX.jpg”] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UITabBarItem中图标尺寸过大问题
当我们给一个UIButton设置Background Image的时候, 是没必要担心图片尺寸过大问题的, 因为图片在Background Image中自适应尺寸被重新绘制了一遍, 所以会刚好铺满Button. 但是UITabBarItem没有Background Image这个属性, 不会重新绘制调整尺寸, 所以你给多大像素的图片, 就会原原本本显示出来. 如下图:
往下讨论之前, 我们先来简单了解一下屏幕分辨率和开发尺寸这两个东东.
不同的iOS设备屏幕有不同的像素分辨率(pixel, 简称px), 对应不同的开发尺寸(point, 简称pt). 比如iPhone 8, 像素分辨率(px)为750x1334, 开发尺寸(pt)为375x667, 尺寸比例系数(Scale Factor)为@2x, 也就是说一个point宽度对应2个pixel宽度.
iOS中, 开发尺寸point对应图片实际的像素点, 例如30x30的图片, 占据iPhone 8 30个point宽度, 60个pixel宽度. 所以, 对于不同尺寸比例系数的iOS设备, 在图片后面加上@1x、@2x或者@3x, 系统会根据设备的比例系数去选择@1x、@2x或者@3x图片. 其中, @1x设备已基本淘汰, 本文不再讨论.
回归正题. 一般的, UITabBar的正常高度 (不含安全区域) 为49个point, 除去文字区域大概剩下30个point. 如果我们给一个分辨率为50x50的图片, 那么显然超出了30point这个区域. 所以, 我们应该准备两种分辨率的图片: 一种是60x60, 加上@2x; 另一种90x90, 加上@3x (例如XXX@2x.png、XXX@3x.png) . 这样就刚好占据30个point宽度.
方法属性
#pragma mark - 属性
// 视图控制器 数组
@property(nullable, nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers;
// 当前选中的VC
@property(nullable, nonatomic, assign) __kindof UIViewController *selectedViewController;
// 当前VC在数组中的index
@property(nonatomic) NSUInteger selectedIndex;
// 导航栏
@property(nonatomic,readonly) UITabBar *tabBar NS_AVAILABLE_IOS(3_0);
#pragma mark - UITabBarControllerDelegate代理方法
// 即将选中某个VC
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController NS_AVAILABLE_IOS(3_0);
// 已经选中某个VC
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;
#pragma mark - 对UIViewController的扩展
@interface UIViewController (UITabBarControllerItem)
// 导航栏项目, 用于管理VC对应的图标、文字、消息提醒等
@property(null_resettable, nonatomic, strong) UITabBarItem *tabBarItem;
// 本尊
@property(nullable, nonatomic, readonly, strong) UITabBarController *tabBarController;
@end
UITabBarItem
继承自UIBarItem, 用于管理VC对应的图标、文字、消息提醒等.
如果用代码创建, 则初始化方法为
// 文字 + 图标 (选中和未选状态均使用这个)
- (instancetype)initWithTitle:(nullable NSString *)title image:(nullable UIImage *)image tag:(NSInteger)tag;
// 文字 + 未选状态中图标 + 未选中状态图标
- (instancetype)initWithTitle:(nullable NSString *)title image:(nullable UIImage *)image selectedImage:(nullable UIImage *)selectedImage NS_AVAILABLE_IOS(7_0);
// 使用系统Item
- (instancetype)initWithTabBarSystemItem:(UITabBarSystemItem)systemItem tag:(NSInteger)tag;
UITabBarSystemItem样式如下(官方文档链接):
如果要改变字体大小颜色, 如下:
NSDictionary *attributes = @{NSFontAttributeName : [UIFont systemFontOfSize:20.0], // 字体类型, 大小
NSForegroundColorAttributeName : [UIColor purpleColor]}; // 字体颜色
[self.tabBarItem setTitleTextAttributes:attributes forState:UIControlStateNormal];
如果要显示消息提醒小圆点, 使用如下属性
@property(nullable, nonatomic, copy) NSString *badgeValue; // default is nil
效果如下
更多属性请继续往下看UITabBarItem的父类UIBarItem.
UIBarItem
An abstract superclass for items that can be added to a bar that appears at the bottom of the screen.
UITabBarItem父类, 用于添加到屏幕底部导航栏上面来显示.
UIBarItem类似于UIButton, 提供了title, image, enabled, action, target等属性方法. 其中有两个属性是我要讨论的, 因为它们出现在storyboard属性设置栏里.
-
landscapeImagePhone
这个是手机横屏时显示的图标. 因为横屏时, 文字显示在图标的右边, 使得图标区域范围变大, 如果不设置这个属性, 原来的image不会改变大小. 设置了这个属性, 可以看看效果 (第一个图标明显变大): largeContentSizeImage (API_AVAILABLE(ios(11.0)), iOS11后可用)
图标的高分辨率版本, 用于渲染辅助UI (例如, 对于需要大文本的视力障碍的用户).