iOS – UITableView的使用

概述

UITableView是iOS开发中最常用的控件之一,大多数应用程序中使用UITableView作为列表来展示内容。例如我们常见的微信程序,以及系统设置,都使用了UITableView或者它的子类进行界面元素的展示。

总体而言,一个UITableView可以包含多个行,但是只包含一个列,每个行就是一个“单元格”,这个单元格对应的类型是UITableViewCell类型。首先简单介绍UITableView的属性:

UITableView的一些属性

UITableView的Content(内容模式)

Content有两种类型:Dynamic Prototypes和Static Cells。

Dynamic Prototypes为动态列表,也就是用于展示超过一屏的内容,可以进行滚动,在滚动过程中,单元格移出屏幕是UITableViewCell对象的进栈操作,已经加载的单元格移入屏幕是UITableViewCell对象的出栈操作(看不懂的找你们句句学姐面壁思过)。详细内容会在UITableViewCell的重用部分介绍。此类型的UITableView,其中的UITableViewCell不得使用IBOutlet进行关联。
Static Cells为静态单元,适用于不超过一屏的内容,不进行重用,可以用IBOutlet进行关联。

UITableView的Style(展示风格)

Style有两种类型:Plain和Grouped。Plain是类似于系统通讯录的样式,而Grouped是类似于系统设置的样式。

UITableView的indexPath(索引路径)

在iOS中,UITableView是利用NSIndexPath类型确定一个UITableViewCell单元格所在的位置的。NSIndexPath包含两个成员,一个是section,一个是row。section代表的是分组号,row代表的是在该分组下的行号(都从0开始编号)。例如section=1,row=2就代表了第2个分组的第3行。

UITableView的UITableViewDataSource(数据源协议)

在加载一个UITableView时,系统会自动调用其UITableViewDataSource代理方法(数据源协议方法),如果UITableView所在的UIViewController没有实现其数据源代理,那么这个iOS程序就会抛出异常。所以要实现UITableViewDataSource协议,具体实现方法详见Objective-C的协议。 在UITableViewDataSource中,规定了一下方法,用于确定UITableView的格式和内容:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

这个方法用于确定UITableView的分组个数,一般这个方法直接返回分组数即可。

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 

这个方法用于确定第section个分组的标题文本,一般通过switch语句来判断section的值,根据不同section来返回不同的字符串。

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section  

这个方法用于确定第section个分组的说明文本,一般通过switch语句来判断section的值,根据不同section来返回不同的字符串。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

这个方法用于确定第section个分组包含的UITableViewCell单元格个数,一般通过switch语句来判断section的值,根据不同section来返回不同整数。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

这个方法在每个UITableViewCell单元格被加载的时候都要调用一次,在其中要实现UITableViewCell的重用,并且要设置UITableViewCell的各种属性,一般利用两层嵌套的switch语句分别判断indexPath的section和row。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath

这个方法在任何一个UITableViewCell单元格被用户点按的时候都会调用,在其中要实现点按不同UITableViewCell的不同行为,包括跳转等,同样地一般利用两层嵌套的switch语句分别判断indexPath的section和row。
当然以上方法编写过程中还有更好的封装方式的写法,把各个Cell和section都封装成数组,原理都相同,这里就不再讲解了。

UITableViewCell的属性及其重用

UITableViewCell的属性

UITableViewCell的主要成员有以下几个:

textLabel:Cell的左侧标题,是UILabel类型
imageView:Cell的左侧图片,是UIImageView类型,举个例子的话就是微信里放头像那个地方
accessoryView:Cell的右侧元素,是UIView类型,可放入任意控件,举个例子的话很多开关都在这
accessoryType:Cell的右侧引导符,一般用UITableViewCellAccessoryDisclosureIndicator,就是大家常见的那个右箭头。这个属性和accessoryView互斥,因为它们占据了同一个位置。
detailTextLabel:Cell的左下侧或右侧详细说明标题:是UILabel类型

UITableViewCell的重用

在Dynamic Prototypes内容模式下,UITableViewCell要求必须进行重用(reuse)。重用方法是在

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

方法中添加如下代码:

NSString *identifier=@"UITableViewCellIdentifier";      //重用标志  
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:(identifier)];
//先尝试从缓存池中取出已经加载的单元格  
if(cell==nil) {
    cell=[[UITableViewCell alloc]initWithStyle:(UITableViewCellStyleSubtitle) reuseIdentifier:(identifier)];
    //如果缓存池中不存在该单元格,则加载该单元格  
} 

其中定义的identifier变量是重用标识符,可以任意起名。然后我们先调用dequeueReusableCellWithIdentifier:方法尝试从系统缓存池中取出已经加载好的UITableViewCell,如果取出失败,则该方法返回nil值,所以再进行判断,取出失败的话再进行alloc分配空间和init初始化。这样就实现了UITableViewCell的重用,提高了效率。UITableViewCellStyleSubtitle是一种Style,这里是和UITableView的Grouped风格配套使用的。

UITableViewCell的其他行为

setSelectionStyle:(UITableViewCellSelectionStyle)

方法用于设置UITableViewCell的点击行为,默认为可以点击,传入参数UITableViewCellSelectionStyleNone可以禁止点击。

deselectRowAtIndexPath:(indexPath) animated:(YES)

方法用于使点击UITableViewCell产生的高亮条立即消失,并带有动画。