到目前为止 我们创建的应用程序 只 向用户 展示 一个单一的视图。但是 在实际应用当中 我们 很有可能 需要根据用户所采取的不同行动 向用户 展示 不同的视图。在这种情况下 我们 需要创建 多个不同的视图,然后 利用 某种机制 允许 用户 在不同的视图之间 转换。这样的机制 有 用户界面导航栏(UINavigationBar) 和 用户界面标签栏(UITabBar)。
关于 标签栏(UITabBar)
典型的标签栏 位于 屏幕的底部。标签栏 会向用户 展现 一组标签,这些标签 一般 包含 文字 有时 也包含 图标。用户 只要点击 这些标签中的某一个 就会被带至 相应的视图。iphone内置的音乐 和 电话应用程序 就是 标签栏的典型应用。在iphone音乐应用程序当中 标签栏 提供了 播放列表、艺人、曲目、视频等标签。用户 点击 不同的标签,就会有 不同的视图 显示 给用户。
理解 多视图应用程序中的视图控制器
在之前的文章中 我们 谈论过 模型-视图-控制器的概念。每个视图 都有 自己的视图控制器 就与 这个概念 有关。在多视图应用程序当中 每个视图 同样 有 自己的视图控制器 用以处理 用户交互 和 内容更新。除此之外 多视图应用程序 还需要 一个额外的控制器。
多视图应用程序 需要 一个肉眼可见的物件,用户 用 它 来从一个视图 切换到 另外一个视图。这种肉眼可见的物件 一般 是 导航栏 或者 标签栏。无论 是 导航栏 还是 标签栏 都属于 视图,于是 他们 都需要 一个视图控制器,在多视图应用程序当中 这样的视图控制器 叫做 底层视图控制器。底层视图控制器 负责 控制 哪些视图 需要显示 在用户面前。作为开发者 我们 不必利用 UIViewController类型的物件 来创建 底层视图控制器,用 UITabBarController类型的物件 或者 UINavigationController类型的物件 来充当 底层视图控制器 则要更好一些。
无论 你 用 什么东西 来充当 底层视图控制器,它 都是 应用程序 启动后 第一个载入的控制器。一旦 底层视图控制器 载入后 它 就要负责 将 第一个视图 展现 给用户,然后 根据用户 与 应用程序的交互 在各个视图之间 切换。
既然 这篇博文 讲述 如何创建 基于标签栏的应用程序,那么 我们 就用 用户界面标签栏控制器(UITabBarController) 作为 我们的底层视图控制器。
创建 项目
创建应用程序的第一步 是 创建 一个Xcode项目。虽然 我们 可以在空模板的基础上 实现 标签栏的功能,但是 我们 也可以将 不少准备工作 留给 Xcode。先点击 基于标签栏的应用程序(Tabbed Application),然后 点击 下一步。
接着 我们 把 产品名称 和 物件类型名称前缀 设定为 TabBar。然后 将 设备家族(Device Family) 设定为 iphone 并且 将 使用故事板(Use Storyboard) 和 单元测试(Unit Test)两个选项 关掉。最后 将 这个项目 创建 在合适的地方。
确定 底层视图控制器
在将 这个应用程序 修改成 满足我们要求之前 我们 需要认识一下 Xcode 是如何使 这个项目 适应 标签栏功能的。
之前提到过 多视图应用程序的关键 是 底层视图控制器。在这个基于标签栏的应用程序当中 底层视图控制器 是 以UITabBarController类型物件的形式 出现的。正是 基于 这点,Xcode 在应用程序代理物件 加入了 一个UITabBarController类型的物件tabBarController。在这里这个例子中 应用程序代理物件 就是 TabBarAppDelegate类型的物件。我们 可以将 TabBarAppDelegate类型的物件 看成 应用程序本身。点选 TabBarAppDelegate.h这个文件,我们 可以看到 这样的语句:
从上面的语句 我们 可以看到 每个TabBarAppDelegate类型的物件 都包含 一个UIWindow *类型的变量window 用来存储 窗口物件的地址 和 一个UITabBarController *类型的变量tabBarController 用来存储 标签栏控制器物件的地址。
再 看看 内容视图控制器
在项目导航器中 我们 可以看到 Xcode 已经添加了 两类属于视图控制器的物件 用来 向用户 展现 内容。这两类物件 分别 是 TabBarFirstViewController 和 TabBarSecondViewController。这两类物件 都有 自己的.h文件、.m文件 和 相应的.xib文件。点击 TabBarFirstViewController.xib这个文件 我们 就可以看到 TabBarFirstViewController类型的物件 是 什么样子:
在TabBarFirstViewController类型的物件中 包含 一个视图物件。视图物件上 有 两个标签,上面的信息 用以提示 开发者。我们 可以在界面创建器里面 修改 这个视图 来满足 我们这个应用程序的要求。我们 先将 视图上的标签 删除。然后 点击 画布上的视图后 再点击 Xcode窗口右侧面板上方第四个标签:
从而 我们 进入了 属性查看器。在属性查看器中 我们 将 视图的背景颜色 修改为 黄色:
接着 我们 将 一个新的标签 拖、放 到视图中央。然后 双击 这个新的标签,在里面 输入 “视图一”
然后 我们 点选 SecondViewController.xib这个文件 并且 重复 刚刚的步骤。这次 将 背景颜色 改成 浅蓝色,中央标签上的文字 写 “视图二”。
初始化 底层视图控制器
应用程序 启动时,会对 TabBarAppDelegate类型的物件 采取 application:didFinishLaunchingWithOptions:这项措施。我们 点选TabBarAppDelegate.m这个文件,然后 找到 application:didFinishLaunchingWithOptions:这项措施:
在这项措施中
这行语句中的[UIScreen mainScreen] 向 UIScreen这类物件 发送了 mainScreen这条消息,从而 获得了 主屏幕物件,然后 对 主屏幕物件 采取 bounds这项措施 从而 获得 主屏幕的尺寸 和 位置。接着 [UIWindow alloc] 为 UIWindow类型的物件,也就是 窗口物件,分配了 内存地址。而 initWithFrame:这项措施 利用 主屏幕的尺寸 和 位置 对 刚刚为窗口物件分配的地址 进行初始化。
这行语句 创建了 一个UITabBarController类型的物件 并 将 其地址 存储在TabBarAppDelegate类型物件所包含的变量tabBarController当中。
这行语句 先向NSArray这类物件 发送了 arrayWithObjects:这条消息,创建了 一个NSArray类型的数组物件,并且 将 viewController1 和 viewController2这个两个物件的地址 添加 到这个数组物件当中;然后 将 这个数组物件的地址 存储 在tabBarController这个物件所包含的变量viewControllers当中。
这行语句 将 标签栏物件tabBarController的地址 存储 在窗口物件window所包含的变量rootViewController当中,从而 将 窗口window的底层视图控制器 设定为了 标签栏物件tabBarController。
然后
这行语句 对TabBarAppDelegate所包含的窗口物件window 采取了 makeKeyAndVisible这项措施,使 这个窗口 呈现 在用户面前。
在创建viewController1这个物件时 我们 采取了 initWithNibName:bundle:这项措施,这项措施的第一个参数 是 .xib文件的名称。我们 点选 TabBarFirstViewController.m这个文件,然后 找到 initWithNibName:bundle:这项措施:
其中第一行语句
对 initWithNibName:bundle:这项措施的实施对象 初始化。其中的关键字self 和 super 指的都是 initWithNibName:bundle:这项措施的实施对象。关键字self 特指 TabBarFirstViewController类型的物件,而 super 则特指 UIViewController类型的物件。
这行语句 判断 initWithNibName:bundle:这项措施的实施对象 是否为 空,如果 不为空的话,则执行 紧接着的两行语句。其中
这行语句 将 实施对象的标题 设定为 First,根据 这个例子的需要 我们 将 这行语句 改为:
然后 我们 点击 TabBarSecondViewController.m这个文件,做出 同样的修改,只不过 将 Second 改成 视图二。
编译 运行 这个程序后,我们 可以看到 如下的效果:
如果 我们 点击 第二个标签,就可以看到 浅蓝色的视图二了。
再 增加 一个视图
了解过 标签控制器 是如何 工作的,现在 我们 为这个应用程序 添加 我们自己的视图。第一步,我们 要创建 一类新的属于UIViewController类型的物件。首先 点击 Xcode的文件菜单,然后 点击 新文件。选择 弹窗右侧iOS标签之下的Cocoa Touch,然后 在弹窗左侧的区域 选择 Objective-C class后 点击 下一步。在新的弹窗中 将 物件类型名称TabBarThirdViewController 填写 在Class标签右侧的文本框中,再 将 物件类型名称UIViewController 填写 在Subclass of标签右侧的文本框中,这 表示 TabBarThirdViewController这类物件 也属于 UIViewController类型。 接着 勾选 With XIB for user interface选项后 点击 下一步,将 TabBarThirdViewController这类物件的文件 存放 在合适的位置。
创建好 TabBarThirdViewController这类物件后,我们 点击 TabBarThirdViewController.xib这个文件,将 用户界面 载入 界面创建器。在界面创建器中 我们 将 视图的背景颜色 修改成 浅绿色,然后 将 一个新的标签 拖、放 到视图的中央 并且 将 标签上的文字 改为 “视图三”。
接下来 我们 点击 TabBarThirdViewController.m这个文件,并且 找到 initWithNib:bundle:这项措施。然后 将 initWithNib:bundle:这项措施 修改成 下面这样:
在这段代码中 我们 将 TabBarThirdViewController类型的视图控制器的标题 设定为了 视图三,并且 将 这个类型的视图控制器在标签栏中的图标 设定为 文件名为first的图片。向UIImage这类物件 发送 imageNamed:这条消息 就可以以某个图片文件为内容 创建 图片物件。
完成了 TabBarThirdViewController这类物件后,就应该 在应用程序启动时,创建 一个这种类型的物件 并且 将 其 添加 到标签栏控制器中。首先 我们 打开 TabBarAppDelegate.m这个文件。要适用 TabBarThirdViewController这类物件,我们 必须在TabBarAppDelegate.m这个文件中 导入 文件TabBarThirdViewController.h,我们 只需要 在@implementation命令上方 加入 下面这行语句 就行了:
然后 找到 application:didFinishLaunchingWithOptions:这项措施。在
这行语句后 添加 下面这行语句:
从而 创建 TabBarThirdViewController类型的物件viewController3。接着 将
这行语句 修改成
从而 将 viewController3这个物件 添加 到标签栏控制器tabBarController当中。
编译 并且 运行 这个程序后,我们 可以点击 标签栏中第三个标签,就可以看到 这样的效果: