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

版本

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

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 (例如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样式如下(官方文档链接):

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 (例如, 对于需要大文本的视力障碍的用户).

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容