iOS开发之UI篇(15)—— UITabBarController

版本

Xcode 10.2
iPhone 6s (iOS12.4)

继承关系

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就是使用标签栏结构:

Clock

结构
我们还是从结构开始讲起. 先来看看这张熟悉的结构图:

结构

在上一章UINavigationController中就出现过这张图, 可以看到, UITabBarController其实和UINavigationController是很相似的. 都是用来管理多个UIViewController的显示, 只不过UINavigationController的导航栏显示在窗口顶部, 而UITabBarController的标签栏显示在窗口的底部, 中间内容则是用于显示当前选中的视图控制器的view.

结构2.0
好像从上图中还看不出多少内容, 不如来看看我的DIY版本:

结构2.0

结构中, UITabBarController管理四个VC, 窗口底部有个UITabBar, 用于存放四个不同的UITabBarItem. 我们可以改变标签栏UITabBar的属性, 比如背景颜色, 背景图片, Item宽度等等. 每个UITabBarItem对应一个VC, 也是VC的一个属性(UITabBarControllerItem扩展). UITabBarItem继承自UIBarItem, 后文再介绍.

什么时候使用UITabBarController
当要显示的多个内容处于平级的时候, 建议使用UITabBarController.

创建

对于这种结构感比较强的界面设计, 当然首选storyboard了.

  1. 拖入一个tab bar controller, 设为is initial view controller
  2. 拖入几个view controller, 从tab bar controller分别引线至view controller, 选择view controllers, 生成segue线.
  3. 如果不用自定义导航栏, 则tab bar controller就不要去动了.
  4. 选中每个VC底部的tab bar item, 在右边栏修改属性的地方, 填写Bar Item里面的Image(未选中状态的图标), 以及Tab Bar Item里面的Selected Image (选中状态的图标). 注意: 如果不设置Image, 光填Selected Image是没有用的.
  5. 事先准备的图标image, 渲染模式应设置为UIImageRenderingModeAlwaysOriginal (Assets.xcassets选中图片, 右边属性栏中Render As选择Original Image), 图片大小准备两种分辨率: 60x60 (@2x), 90x90 (@3x). 如果有疑惑继续往下看.
  6. 补充一点, 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 (例如[email protected][email protected]) . 这样就刚好占据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样式如下(官方文档链接):

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属性设置栏里.

  1. landscapeImagePhone
    这个是手机横屏时显示的图标. 因为横屏时, 文字显示在图标的右边, 使得图标区域范围变大, 如果不设置这个属性, 原来的image不会改变大小. 设置了这个属性, 可以看看效果 (第一个图标明显变大):
    图标变大

  2. largeContentSizeImage (API_AVAILABLE(ios(11.0)), iOS11后可用)
    图标的高分辨率版本, 用于渲染辅助UI (例如, 对于需要大文本的视力障碍的用户).

猜你喜欢

转载自blog.csdn.net/u012078168/article/details/100976249