iOS UIKit:TableView之表格创建(1)
Table View是UITableView类的实例对象,其是使用节(section)来描述信息的一种滚动列表。但与普通的表格不同,tableView只有一行,且只能在垂直方向进行滚动。tableView由多个section组成,而section又由行(row)组成,也可将行称为单元格(cell)。Cell是UITableViewCell类的实例对象。
1 样式
UIKit框架提供了一些标准样式供设计UITableView和UITableViewCell的结构和显示外观,同时也提供一些单元格的附加显示方式。
1.1 Table View
UITableView类有两种主要的样式:plain 和grouped,两者的差别主要是在外观上。
1.1.1 Plain类型
Plain样式是table view的一种常规样式,该类型的section间距非常细微。而且每个section对象都有自己的header和footer标题,当用户滚动表格时,section的header标题会跟着浮动到顶部,同时section的footer则会浮动到表格的底部。如图 11所示。
图 11 A table view in the plain style
若使用了索引表(indexed list)则会在表格的右侧显示每个section的header标题,当用户触碰了某一项索引时,视图会滚动到相应的section中,从而索引表起到了导航的作用。如图 12所示。
图 12 A table view configured as an indexed list
1.1.2 Grouped类型
Grouped样式的表格也可以展示数据,但每个section之间都有非常明确的间距,如图 13(左)所示。同时Grouped样式表格的每个section的位置和尺寸都是固定,如图 13(右)所示。
图 13 A table view in the grouped style
1.2 Cell View
除了为UITableView定义了两种类型的样式外,UIKit框架还为 cell也定义了四种类型的样式。同时用户还可以自定类型的cell样式。
1.2.1 Basic类型
这种类型的cell是由常量UITableViewCellStyleDefault来描述的,其使得table view的cell只拥有一个简单标题和可选的图像。如图 14所示。
图 14 Default table row style
1.2.2 Subtitle类型
该类型的table view cell除拥有一个左对齐的标题,同时还有一个灰色的副标题,当然也可以设置图像。可以通过UITableViewCellStyleSubtitle常量进行描述,如图 15所示的效果图。
图 15 Table row style with a subtitle under the title
1.2.3 Right Detail类型
该类型的table view cell也有一个左对齐的标题,但副标题是蓝色的右对齐,同时不允许设置图像。可以通过UITableViewCellStyleValue1常量进行描述,如图 16所示。
图 16 Table row style with a right-aligned subtitle
1.2.4 Left Detail类型
该类型的table view cell比较特殊,其标题位于行的左侧,但是右对齐的且默认为蓝色;而副标题位于行的右侧,但是为左对齐。同时这种类型样式不允许设置图像。可以通过UITableViewCellStyleValue2常量进行描述,如图 17所示。
图 17 Table row style in Contacts format
1.3 Accessory Views
UIKit框架还Table view提供了三种附加视图,如表 11所示。
表 11 accessory views
accessory views |
Name |
Description |
Disclosure indicator |
使用UITableViewCellAccessoryDisclosureIndicator常量。若需在另一个层次的table view中显示更详细的信息,则可以使用这种类型。 | |
Detail disclosure button |
使用UITableViewCellAccessoryDetailDisclosureButton常量,可以在另一个view中显示更详细的信息(可以为 table view,也可以不是)。 | |
Checkmark |
使用UITableViewCellAccessoryCheckmark常量。可以使用这种样式来让用户进行选择,可以是多选,也可以是单选。 |
2 API概述
UIKit为table view编程提供了两个protocols,及一个category。
2.1 View
Table view本身是UITableView的实例对象,可以使用这个类的方法来配置table view的外观和行为,同时可以用于管理section、row和滚动视图。UITableView继承自UIScrollView类,该类定义了视图的滚动行为,但UITableView只允许在垂直方向上进行滚动操作。
2.2 Data Source与Delegate
一个UITableView对象必须要有一个delegate和一个data source对象。遵守MVC设计模式,data source 用于协调数据模型和视图;而delegate管理视图的外观和行为。其实data source和delegate经常为同一个对象。
1) Data source
Data source对象是继承自UITableViewDataSource协议,并且必须实现该协议的其中两个方法:
-
tableView:numberOfRowsInSection:该方法是告诉UIKit每一section有多少行,即有多少个cell。
-
tableView:cellForRowAtIndexPath:该方法向UIKit返回每一行中的cell对象。
另外还有一些可选的方法用于配置section的数目、header和footer,及配置是否支持添加、移除和跟踪row。
2) Delegate
Delegate对象是继承自UITableViewDelegate协议,这个协议没有必须要实现的方法。其提供了很多配置table view可视化外观的方法,及一些section管理方法。 同时app还可以使用一个便利的类:UILocalizedIndexedCollation。该类帮助data source来组织索引列表的数据;同时当用户点击row时,该类能以非常合适的方式来显示section对象。
2.3 Controller
根据UIKit提出的MVC设计模型,UITableView属于V部分元素,其需要指定C部分元素进行管理。对于control对象,有两种实现方式:
1)继承UIViewController类
若用户直接继承UIViewController类来管理UITableView,那么用户需实现UIViewController类的两个方法,其实现的具体任务为:
-
viewWillAppear:方法
即在table view展示之前,通过调用UITableView对象的deselectRowAtIndexPath:animated:方法来清理选中的row。
-
viewDidAppear:方法
即在table view展示了之后,应向UITableView对象发送flashScrollIndicators消息,从而刷新视图。
2) 继承UITableViewController类
UITableViewController类已经实现了Delegate和Data Source协议,同时实现了一些细节工作。如当table view将要显示视图时,或是table view完成了显示内容时,UITableViewController类能帮忙清理section对象。另外还能以合适的方式响应用户交互事件;最重要的是UITableViewController类有一个tableView属性,其指向UITableView对象。
注意:
Apple虽然推荐采用继承UITableViewController类来管理tableView,但若一个视图中还拥有其它的子view对象,那么应该采用继承UIViewController类的方式,而不是继承UITableViewController类,因为UITableViewController类会将UITableView对象填充整个屏幕。
当然若在interface builder的库中直接拖动一个 table view controller对象到设计界面中,那么则需要继承UITableViewController类。
2.4 Paths
很多table view方法都使用NSIndexPath对象作为参数。该对象声明了在table view中单元格(cell)的路径,其有两个属性:section和row。通过这个对象能标识二维空间table view中cell的位置。
2.5 Cells
在table view中的行其实是一个单元格,即是UITableViewCell对象。该类提供了很多方法用于管理和配置单元格。用户可以直接继承该类,从而自定义cell的外观和样式。
3 创建与配置
3.1 基本过程
在创建table view过程中,有几个实体对象之间会发生交互:viewController、tableView、data source和delegate。其中viewController、data source和delegate一般是同一个对象,如下是创建基本tableView的过程,如图 31所示。
a) viewController指定frame和style值来创建UITableView实例对象,其中可以使用programmatically或storyboard方式。
b) 用户(ViewController)为UITableView对象设置data source和delegate对象,然后向其发送reloadData消息。
c) UITableView对象调用data source对象的numberOfSectionsInTableView:方法,从而获得tableView中section的数量。该方法为可选方法,默认返回1。
d) UITableView对象调用data source对象的tableView:numberOfRowsInSection:方法,从而获得每个section中row的数量,该方法为必须实现的方法。
e) UITableView对象调用data source对象的tableView:cellForRowAtIndexPath:方法,从而获得每个row中的UITableViewCell对象,该方法为必须实现的方法。
图 31 Calling sequence for creating and configuring a table view
3.2 Storyboard方式
3.2.1 创建tableView
在interface builder的库中有两种控件:table view和table view controller,从而可以采用两种方式来创建表格。
1) table view控件
若使用table view控件,则可自由配置content view中的内容,如可以添加更多的控件,而不是仅仅只有一个table view控件。当然这种方式需要用户进行更多配置,如界面的布局等。如下是创建和配置的步骤:
-
直接从库中拖动一个table view控件到某个UIViewController的rootView内。
-
创建一个继承UIViewController类的子类,同时创建遵守UITableViewDataSource和UITableViewDelegate协议的类,在该类中实现data source两个必选方法。
-
在UIViewController子类中设置tableView对象的data source和delegate对象。
-
在indentity inspector中指定相应的class类,并指定tableView的样式类型。
2) table view controller控件
也可以直接使用table view controller控件,但由于table view controller控件把整个屏幕除了导航栏和状态栏都被table view所填满,所以无法再添加其它的视图,其自定义方式比较受限,但若只是使用table view则比较简单。如下是创建和配置的步骤:
-
直接从库中拖动一个table view controller控件到中央的编辑器内。
-
创建一个UITableViewController类的子类,并实现UITableViewDataSource协议的两个必选方法(其它方法也可实现)。
-
在indentity inspector标签中指定相应的class类,并指定tableView的样式类型。
3.2.2 设置tableview内容
tableView的内容就是cell,其中有两种方式来创建cell:Dynamic和Static。
1) Dynamic prototypes
这种方式是指在interface builder中创建一个cell原型(模板),然后在data source的相应方法中通过标识符获取原型cell类,接着实例化模板对象并返回。如图 32所示的cell原型(左),及设置Identifier的内容(右)。
图 32 A dynamic table view
2) Static cells
这种方式为tableView指定静态的布局内容和cell的数量。
图 33 A static table view
注意:通过interface builder创建tableView默认是动态原型模型,若希望使用static cell方式,需要对其进行某些设置,如图 34所示:
-
选中table view;
-
显示Attributes inspector;
-
在其content菜单中选择Static Cells选项。
图 34 static cell配置
3.3 Program方式
3.3.1 实现协议
通过程序的方式创建table view,一样需要实现协议的相应方法;若是继承UIViewController类,则同时还需实现UITableViewDelegate和UITableViewDataSource协议,并实现相应的方法。如下所示。
2 @property (nonatomic, strong) NSArray *timeZoneNames;
3 @end
3.3.2 创建和配置
在实现相应协议后,即可创建table view对象,并进行相应配置,可按如下方法进行:
a) 创建并初始化UITableView对象;
b) 设置data source和delegate对象;
c) 调用UITableView对象的reloadData方法。
如下是创建一个tableView对象,并设置到controller的view的属性:
2 {
3 UITableView *tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
4 tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
5 tableView.delegate = self;
6 tableView.dataSource = self;
7 [tableView reloadData];
8
9 self.view = tableView;
10 }
3.4 查询数据
在创建一个UITableView对象后,controller对象将向UITableView对象发送reloadData消息,从而UITableView对象通过查询data source和delegate对象的消息来显示相应section和row对象。
如下所示是实现一个data source和delegate协议方法的简单示例:
2 return [regions count];
3 }
4 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {//必选:返回每个section中row的数量
5 Region *region = [regions objectAtIndex:section];
6 return [region.timeZoneWrappers count];
7 }
8 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {//可选:返回每个section中的header标题
9 Region *region = [regions objectAtIndex:section];
10 return [region name];
11 }
12 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {//必选:返回每个row中的cell对象
13 static NSString *MyIdentifier = @"MyReuseIdentifier";
14 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
15 if (cell == nil) {
16 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
17 }
18 Region *region = [regions objectAtIndex:indexPath.section];
19 TimeZoneWrapper *timeZoneWrapper = [region.timeZoneWrappers objectAtIndex:indexPath.row];
20 cell.textLabel.text = timeZoneWrapper.localeName;
21 return cell;
22 }
3.5 索引列表
Table view通过索引列表能够快速进行导航,其中UITableView的plain和grouped样式都可配置索引列表。而配置索引列表只需实现UITableViewDataSource协议的三个方法:
1) sectionIndexTitlesForTableView:其返回表格右边的索引标题,是一个NSString类型的数组。
2) tableView:titleForHeaderInSection:其返回每个section的header标题,是一个NSString对象。
3) tableView:sectionForSectionIndexTitle:atIndex:其返回section的索引,即当点击表格右边的索引时,将滚动到section的位置,是一个整型值。
如在一个tableView中有8个section,则与索引列表的三个方法所实现如下:
2 {
3 NSArray<NSString*>* array = @[@"I0",@"I1",@"I2",@"I3",@"I4",@"I5",@"I6",@"I7"];
4 return array;
5 }
6 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
7 {
8 NSString* title = [[NSString alloc] initWithFormat:@"T%ld",section];
9 return title;
10 }
11
12 - (NSInteger)tableView:(UITableView *)tableView
13 sectionForSectionIndexTitle:(NSString *)title
14 atIndex:(NSInteger)index
15 {
16 return index;
17 }
图 35 索引列表效果图