九十八、创建 有导航功能的列表视图应用程序

本文详细介绍了如何在iOS应用中实现具备导航功能的列表视图,包括理解导航控制器、创建底层视图控制器、添加数据源、实现列表功能、连接两个视图控制器以及实现导航功能的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在先前的博文当中,我们  初步  了解了  列表视图,并且  创建了  一个简单的列表视图应用程序。不过  我们先前创建的列表视图应用程序  并不具备  导航功能。然而  在大多数情况中  表格视图  都要 和  导航功能  结合起来,这样  才能  使  用户  在不同的视图当中  切换。于是  在这一篇博文当中  我们  主要  关注  如何创建  具备导航功能的列表视图应用程序。

理解  导航控制器

具备导航功能的应用程序  会利用  成体系的方法  向用户  展示  信息。这样的应用程序  一般  包含  一个导航栏(UINavigationBar类型的物件)  和  一些列表视图。用户  点选  列表视图中的某个项目后,与之相应的视图  就会显示  在用户面前。同时  导航栏  会显示出  当前视图的标题  和  一个返回按钮,以便  用户  能够  回到  先前的列表视图。你  可以花  点时间,好好  用用  iphone的邮件应用程序  和  音乐应用程序,从而  更好地  理解  这个概念。

当我们  开发  具有导航功能的应用程序时,核心  是  导航控制器。另外  每个视图  都需要  一个相应的视图控制器。导航控制器  会维护着  一个由许多视图控制器组成的堆栈。每当一个视图  显示出来时,相应的视图控制器  就会被推到  导航控制器堆栈的顶端  变为  活跃的状态。导航控制器  会  自动  显示出  导航栏  和  返回按钮。当用户  点击  导航栏上的返回按钮时,当前活跃的视图控制器  就会被导航控制器  从堆栈的顶端  推走,而  被推走的视图控制器下方的那个视图控制器  就会成为  当前活跃的视图控制器,这样  用户  就回到了  上一级视图。

应用程序  启动时,第一个列表视图所在的视图控制器  叫做  底层视图控制器。而  底层视图控制器  不能从导航控制器堆栈中  被推走。

大致  了解  接下来的例子

在接下来的例子当中  我们  要  同时  实现  列表视图  和  导航功能。完成过后  我们的应用程序  会显示出  一个列表视图,这个列表视图  会列举出  歌手的名字。当我们  选择  某个歌手的名字后,会有  另外一个列表视图  显示出来,并且  列举出  这位歌手演唱的曲目。

既然我们这个例子的目的  是  同时  实现  列表视图  和  导航功能  而不是  处理  数据,所以  我们  仅仅  用  很简单的代码  来为  歌手列表  和  曲目列表  提供  数据。在实际应用中  列表视图所需的数据  都是  从数据库中  拉取的。

创建  项目

为了实现  我们这个例子,我们  需要创建  一个新的项目。于是  我们  启动  Xcode,然后  点击  Create a new Xcode project选项。在左边面板中  选择  iOS Application,再  在右边的面板中  选择  Empty Application(空应用程序)。点击  下一步后,将  产品名称  和  物件类型名称前缀  都设定为  TableView。接着  将  设备家族  设定为  iphone,而  其他选项  都取消。最后  点击  下一步,将  这个项目  存储  在适当的位置。

添加  底层视图控制器

由于我们  选择了  空应用程序模板,所以  Xcode  仅仅  为我们  生成了  应用程序代理的文件。于是  第一步  我们  需要  给这个项目  添加  底层视图控制器。

先前  提到过  一个导航控制器  需要  一个底层视图控制器。当这个导航控制器  被创建出来时,这个底层视图控制器中的视图  就是  呈现给用户的第一个视图。在考虑  导航控制器之前,我们  先要创建  底层视图控制器  及  其所包含的视图。底层视图控制器  必须属于  UIViewController类型  或者  这个类型中的小类。既然  我们这个例子的目标  是  实现  列表视图,所以  我们  需要使用到  UITableViewController类型的物件。

按住  键盘上的Control键,同时  用  鼠标  点击  Xcode窗口左侧项目导航面板顶端的TableView。再  在弹出的菜单中  点击  New File…选项。在新弹出的小窗左侧面板中  选择  iOS标题之下的Cocoa Touch选项,接着  选择  Objective-C class文件模板后  点击  下一步。在接下来的窗口中  将  Class标签右侧的文本框  填写成  RootViewController,表明  我们  要创建  一类叫做RootViewController的物件。然后  在Subclass of选项中  选择  UITableViewController,表明  每个RootViewController类型的物件  同时  也属于  UITableViewController类型。别忘了  勾选  With XIB for user interface选项,而  Targeted for iPad选项  则不管。点击  下一步后,Xcode  会为RootViewController这类物件  生成  RootViewController.h、RootViewController.m  和  RootViewController.xib三个文件:

Root View Controller,RootViewController

创建  导航控制器

下一步  我们  需要编写  一些代码  来创建  导航控制器,并且  将  底层视图控制器  添加  到导航控制器当中。创建导航控制器的理想位置  是  应用程序代理。首先  我们  选择  TableViewAppDelegate.h这个文件,并且  在

这行语句之前  添加  这样一行语句:

这样  每个TableViewAppDelegate类型的物件中  都包含  一个变量navigationController,用于存储  导航控制器的地址。

接着  我们  要生成navigationController  和  setNavigationController:这两项措施。我们  选择  TableViewAppDelegate.m这个文件,并且  在@implementation命令后  加上

这行语句。

由于  应用程序  启动后,会创建  一个TableViewAppDelegate类型的物件,并且  对 这个物件  采取  application:didFinishLaunchingWithOptions:这项措施,所以  我们  打开  TableViewAppDelegate.m这个文件  并且  找到  application:didFinishLaunchingWithOptions:这项措施,将  这项措施  修改为  下面这样:

在这项措施中

这行语句  利用  RootViewController.xib这个文件中的设计  创建了  一个RootViewController类型的物件  并且  将  其地址  存储  在变量rootViewController当中。这个RootViewController类型的物件  我们  用作  底层视图控制器。

另外  为了使用  RootViewController类型的物件,别忘了  在TableViewAppDelegate.h中  加入

这行语句  或者

这行语句

这行语句  创建了  一个导航控制器  并且  将  上一行语句中创建的底层视图控制器  添加  到  这个导航控制器中。最后  将  这个导航控制器的地址  存储  在TableViewAppDelegate类型物件所包含的变量navigationController当中。

这行语句中  我们  先向UIScreen这类物件  发送了  mainScreen这条消息  从而  得到了  主屏幕物件。接着  我们  对主屏幕物件  采取了  bounds这项措施  从而  得到了  主屏幕的横、纵坐标  和  高、宽。然后  我们  给窗口物件,也就是  UIWindow类型的物件,分配了  内存地址,并且  对  其  采取了  initWithFrame:这项措施  从而  将 这个窗口物件的位置、尺寸  设定为  与主屏幕一致的数值。最后  我们  把  这个窗口物件的地址  存储  在TableViewAppDelegate类型物件所包含的变量window当中。

这行语句  向UIColor这类物件  发送了  whiteColor这条消息  从而  获得了  代表白色的物件。然后  将  TableViewAppDelegate类型物件所包含的窗口物件window的背景颜色  设定为  白色。

这行语句  将  导航控制器物件中所包含的视图  作为子视图  添加到  窗口物件上。

这行语句  对  应用程序的窗口物件  采取了  makeKeyAndVisible这项措施,将  其  变为  关键窗口  并且  肉眼可见。

在底层视图控制器中  组织  数据

底层视图控制器  将要扮演  数据源  和  列表视图代理的角色。所以  我们  需要编写  一些适用于底层视图控制器的措施  用来组织  数据  和  实现  列表功能。

首先,我们  打开  RootViewController.h这个文件,再  在@end命令前  加入  这行语句:

这样  每个RootViewController类型的物件  都包含  一个数组物件singers  用于存储  歌手的名字。

接着,我们  打开  RootViewController.m这个文件  并且  在@implementation命令后  加入

这行语句,从而  生成  singers  和  setSingers:这对措施。

一旦  底层视图控制器中包含的视图  加载后,就会  对底层视图控制器  采取  viewDidLoad这项措施,所以  我们  要在viewDidLoad这项措施当中  组织  数据。在RootViewController.m这个文件中  找到  viewDidLoad这项措施  并且  将  其  修改为  这样:

在这项措施中  我们  为  数组物件  分配了  内存地址  并且  将  两位歌手的名字  装进 这个数组物件。最后  将  这个数组物件的地址  存储  在底层视图控制器所包含的变量singers当中。

底层视图控制器中的视图  卸载后,就会  对底层视图控制器  采取  viewDidUnload这项措施。所以  我们  需要编写  viewDidUnload这项措施,就像  这样:

从而  将  底层视图控制器所包含的数组物件singers  从内存  清理出去。

编写  代码  在列表视图中  显示  数据

当列表视图  显示出来时,我们  必须告诉  列表视图  要显示  多少组数据  以及  多少排数据。通过采取  numberOfSectionsInTableView  和  numberOfRowsInSection这两项措施,列表视图  就能知道  需要显示  多少组数据  以及  多少排数据。于是  我们  打开  RootViewController.m这个文件。再  找到  numberOfSectionInTableView这项措施  并且  修改成  这样:

采取  这项措施后  得到的结果  是  整数1,表明  列表视图  要显示出  一组数据。

接着  找到  numberOfRowsInSection这项措施  并且  修改成  这样:

在这项措施中  我们  对底层视图控制器所包含的数组物件singers  采取了  count这项措施  从而  数出  数组物件singers中元素的数量,也就是  歌手名字的数量。然后 将  歌手名字的数量  作为结果  传递回去。列表视图  就会显示出  同样数量的单元格。

列表视图  知道了  要显示  多少组数据  和  多少排数据,接着  我们  要为列表视图的各排  创建  单元格  并且  把  每排需要显示的数据  存储  到这一排的单元格物件中。这个  可以通过  对  底层视图控制器  采取  cellForRowAtIndexPath这项措施  办到。还是  在RootViewController.m这个文件当中,我们  找到  cellForRowAtIndexPath这项措施  并且  将  这项措施  修改成  这样:

在这项措施中  Xcode  已经帮助  我们  完成了  大多数代码。这些代码的作用  在先前的文章中  已经介绍过了。cellForRowAtIndexPath这项措施  附带了  一个参数  就是  indexPath  表示  索引路径。而  唯一需要我们编写的代码  就是  这一行:

在这行代码中  我们  对索引路径indexPath  采取了  row这项措施,从而  获取  当前的排数。接着  将  当前的排数  作为参数  传递给  objectAtIndex:这项措施  并且  对数组物件singers  采取了  objectAtIndex:这项措施,从而  将  与当前排数所对应的歌手名字  读取出来。最后  将  当前单元格cell所包含的标签textLabel中的文本  设定为  与当前排数相对应的歌手名称。

最后

这行语句  将  我们准备好的单元格cell  作为结果  传递回去。

我们  编译  并且  运行  这个程序,可以看到  如下的结果:

TableView,UITableView

根据  我们的设想,如果  我们  现在  点击  其中一个歌手的名字,就会弹出  另外一个列表视图  并且  列举出  这位歌手所演唱的曲目。但是  到目前为止  如果  我们  点击  任何一个歌手的名字,什么事情  都不会发生。这  正是  我们下一步要完成的工作。

创建  第二个视图控制器

为了  创建  显示某个歌手所唱曲目的视图控制器,我们  按住  Ctrl键  并且  点击  Xcode窗口左侧项目导航器上方的TableView条目,接着  在弹出的菜单中  点击  新文件(New File…)。在接下来的弹窗左侧的iOS部分  点选  Cocoa Touch。然后  在弹窗左侧  点击  Objective-C class模板。最后  点击  下一步(Next)。

点击  下一步过后,会出现  一个新的窗口。在新的窗口中  将  物件类型名称Class  设定为  SongsViewController  并且  将  这类物件所属的类别Subclass of  设定为  UITableViewController。这  就表示  我们要创建一类SongsViewController类型的物件,同时  这类物件  包含  在UITableViewController这类物件当中。然后  我们  要确保  没有选择  Targeted for iPad这个选项,还要确保  选择了  With XIB for user interface这个选项。

最后  点击  下一步,将  SongsViewController这类物件的文件  存储  在合适的地方。

接下来  我们  打开  RootViewController.h这个文件,并且  将  这个文件  修改成  这样:

这样一来  每个  底层视图控制器  都包含  一个SongsViewController类型的物件songsViewController  用于显示  某个歌手所唱曲目。

将  第二个视图控制器  和  底层视图控制器  连接起来

接着  我们  需要  在RootViewController.xib这个文件中  创建  一个SongsViewController类型的物件  并且  将  其  与RootViewController.h中创建的SongsViewController类型的物件songsViewController  连接起来。于是  我们  打开 RootViewController.xib这个文件  并且  从物件库中  拖  一个视图控制器(UIViewController类型)  放  到画布中。这样一来  我们  可以看到  每个RootViewController类型的物件  都包含  两个物件:

xib

然后  我们  点击  刚刚添加到画布中的视图控制器  并且  点击  Xcode窗口右侧面板中第三个标签  进入  属性查看器。接着  将  新添加的视图控制器的类型  由UIViewController  改为  SongsViewController:

Identity Inspector

最后  按住  control键  并且  点击  File’s Owner图标:

File's Owner

鼠标  不放  一直  拖  到Songs View Controller图标:

放开  鼠标后,就会弹出  这样的菜单:

Outlets

点击  songsViewController选项后,RootViewController.h中创建的SongsViewController类型的物件songsViewController  和  RootViewController.xib中的SongsViewController类型的物件  就是  同一个物件了。

实现  第二个视图控制器的功能

因为  SongsViewController类型的物件  用来充当  其所包含的列表视图的数据源,所以  我们  要编写  一些代码  来存储  各位歌手所唱的相应曲目。

首先  我们  打开  SongsViewController.h这个文件  并且  将  其  修改成  这样:

从而  每个SongsViewController类型的物件  都包含  一个数组物件songs  用以存储  某个歌手所唱的曲目。接着  我们  需要生成  songs  和  setSongs:这两项措施  以便 对每个SongsViewController类型的物件所包含的songs物件  进行读写。于是  我们  打开  SongsViewController.m这个文件  并且  在@implementation命令后  加上  这行语句:

同时  我们  需要确定  SongsViewController类型物件中的列表视图  需要显示  多少分组  以及  每个分组  显示  多少排数据。所以  我们  在SongsViewController.m这个文件中  找到  numberOfSectionInTableView  和  numberOfRowsInSection这两项措施  并且  将  他们  修改成  这样:

这样一来  SongsViewController物件中的列表视图  就会显示出  一个分组,这个分组显示的数据排数  与  当前歌手所唱的曲目数量  一致。

下一步任务  是  将  各个歌手所唱的曲目  存储  在SongsViewController物件所包含的数组songs当中。我们  可以在viewDidLoad这项措施当中  完成  这个任务。SongsViewController类型物件中的视图  加载时  就会采取  viewDidLoad这项措施。直到SongsViewController类型物件中的视图  被清理  并且  再次  加载时,viewDidLoad这项措施  才会得以执行。如果  我们  初始化  数据  一次,viewDidLoad这项措施  是  理想的选择。但是  在我们现在这个应用程序中,用户  每次  可能选择  不同的歌手。所以  SongsViewController类型物件中的视图  每显示出来一次,我们  都需要重新初始化  这个物件中的数组songs。于是  我们  需要找到  一项措施,而且  每次  SongsViewController类型物件中的视图  显示出来时,这项措施  都要能够得以执行。而  viewWillAppear这项措施  每当  视图控制器中的视图  即将显示出来时  都会得以执行,所以  我们  应该在viewWillAppear这项措施当中  对SongsViewController类型物件中的数组songs  进行初始化。我们  打开  SongsViewController.m这个文件  并且  添加  viewWillAppear这项措施:

在这项措施中  我们  利用  SongsViewController类型视图控制器的标题  来判断  用户  选择了  哪位歌手。在后面的代码中  我们  会看到  当用户  在底层视图控制器的列表视图中  选择  某个歌手后,我们  会把  显示这个歌手所唱曲目的SongsViewController类型视图控制器的标题  设定为  这位歌手的名字。

这行语句  对SongsViewController类型物件所包含的列表视图tableView  采取  reloadData这项措施。这样  可以保证  每次SongsViewController类型物件中的视图  显示出来时,其中的列表视图  都会显示  最新的数据。

当SongsViewController类型物件中的视图  卸载时,我们  要保证  这个物件中的数组songs  也被清理掉,所以  我们  在SongsViewController.m这个文件中  加入  下面的措施:

接下来  我们  需要为SongsViewController类型物件中的列表视图  创建  单元格。我们  在SongsViewController.m这个文件中  找到  cellForRowAtIndexPath:这项措施  并且  修改成  这样:

cellForRowAtIndexPath这项措施  在执行的时候  会收到  参数indexPath,也就是 索引路径。

这行语句  对索引路径indexPath  采取了  row这项措施,从而  得知  当前正在准备第几排的单元格。然后  对SongsViewController类型物件所包含的数组songs  采取objectAtIndex:这项措施  从而  将  与当前单元格对应的曲目名称  读取出来。最后  将  与当前单元格对应的曲目名称  存储  在正在准备的单元格cell当中。

这行语句  将  准备好的单元格cell  作为结果  传递回去。

编写  代码  实现  导航功能

接下来  我们  需要修改  底层视图控制器的功能,以便  用户  在底层视图控制器中  选择  某个歌手后,显示  这个歌手所唱曲目的视图控制器,也就是  SongsViewController类型的物件,能够显示出来。当用户  选择  列表视图中的某个项目时,didSelectRowAtIndexPath这项措施  就会得以实施。所以  我们  要在didSelectRowAtIndexPath这项措施中  实现  导航功能。

首先  我们  打开  RootViewController.m这个文件  并且  在@implementation命令后  加上  这行语句

这样一来  我们  就生成了  songsViewController   和  setSongsViewController:这两项措施,我们  就可以对  底层视图控制器中所包含的SongsViewController类型的物件songsViewController  进行访问了。

然后  在RootViewController.m这个文件中  找到  didSelectRowAtIndexPath这项措施  并且  将  这项措施  修改为  下面这样:

在这项措施中  我们  先判断  用户  选择了  列表视图中的第几排。然后  根据用户的选择  将底层视图控制器中所包含的视图控制器songsViewController的标题  设定为  相应的歌手名称。

这行语句  对底层视图控制器所包含的导航控制器navigationController  采取了  pushViewController:animated:这项措施  并且  将  底层视图控制器所包含的视图控制器songsViewController  作为参数,从而  将  songsViewController这个视图控制器  推到  导航控制器堆栈的顶端。如果  要把导航控制器堆栈顶端的视图控制器  推开,我们  需要对导航控制器  采取  popViewControllerAnimated这项措施。

编译  并且  运行  这个程序后,我们  任意  点击  一位歌手的名字,我们  可以看到  这样的效果:

UITableView,UINavigationController

这时候  我们看到的就是  就是  SongsViewController类型的视图控制器物件songsViewController。而  songsViewController这个物件  就包含  在RootViewController类型的底层视图控制器物件当中。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值