使用 UITableView 创建表格应用演练(3)——使用区段分类显示表格数据
上一篇 使用 UITableView 创建表格应用演练(2)——从plist文件加载并显示数据" 完成后,“微博关注人”这个应用虽然距离最终的完成还有不小的距离,但从视觉上已经比演练(1)完成时有了不小的改进。:]
细心的朋友们在上次演练中已经发现,我们定义的数据结构中,有一个名为“类别”的字段,这个字段的设置主要用于帮助我们更好地管理我们的关注对象。本文演练仅仅涉及一个问题,就是如何按照“类别”在表格中分区段显示数据。本此演练之后,相信您会对iOS中的数组(NSMutableArray)和plist文件的使用也会有一个新的理解。
一. 开始之前
开始之前,我们需要简单回顾一下上一次的一些内容,这样便于我们演练的开始。
1. 在FocusUsers.plist文件中顺序存放所有关注用户的数据;
2. 我们定义了一个名为JOYFocusUser的类来存放每个用户的信息;
3. 我们在视图控制器中用到了一个NSMutableArray数组存放plist文件内容,并通过JOYFocusUser类做为映射,便于程序编写过程中的访问。
那么现在问题出来了——从plist文件中加载过来的数据是一个序列的,而分区段显示数据时,单一序列的数组显然有些难以胜任,这个时候我们需要做一个中转。如下图所示:
如果我们从上一讲中的单一序列,变成有图所示的二维序列问题似乎就好解决了。:]
好,思路有了,现在让我们马上动手。
二. 数据调整
1. 在导航区域,点击“FocusUsers.plist”文件,打开我们上次演练中建立的plist文件;
2. 在“FocusUsers.plist”上点击鼠标右键,选择“Open As”“Source Code”,并使用下列代码替换我们上次使用的plist内容:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 <plist version="1.0"> 4 <array> 5 <array> 6 <dict> 7 <key>UserName</key> 8 <string>爱Apps</string> 9 <key>Image</key> 10 <string>爱Apps.jpeg</string> 11 <key>WebSite</key> 12 <string>http://weibo.com/iapps</string> 13 <key>Favorite</key> 14 <real>3.5</real> 15 <key>Category</key> 16 <string>苹果咨询</string> 17 </dict> 18 <dict> 19 <key>UserName</key> 20 <string>苹果汇</string> 21 <key>Image</key> 22 <string>苹果汇.jpeg</string> 23 <key>WebSite</key> 24 <string>http://weibo.com/appleus</string> 25 <key>Favorite</key> 26 <real>3.5</real> 27 <key>Category</key> 28 <string>苹果咨询</string> 29 </dict> 30 <dict> 31 <key>UserName</key> 32 <string>数码iPhone大百科</string> 33 <key>Image</key> 34 <string>数码iPhone大百科.jpeg</string> 35 <key>WebSite</key> 36 <string>http://weibo.com/gx110</string> 37 <key>Favorite</key> 38 <real>3.5</real> 39 <key>Category</key> 40 <string>苹果咨询</string> 41 </dict> 42 </array> 43 <array> 44 <dict> 45 <key>UserName</key> 46 <string>新浪视野</string> 47 <key>Image</key> 48 <string>新浪视野.jpeg</string> 49 <key>WebSite</key> 50 <string>http://weibo.com/wboard</string> 51 <key>Favorite</key> 52 <real>3.5</real> 53 <key>Category</key> 54 <string>官方机构</string> 55 </dict> 56 </array> 57 <array> 58 <dict> 59 <key>UserName</key> 60 <string>李开复</string> 61 <key>Image</key> 62 <string>李开复.jpeg</string> 63 <key>WebSite</key> 64 <string>http://weibo.com/kaifulee</string> 65 <key>Favorite</key> 66 <real>3.5</real> 67 <key>Category</key> 68 <string>IT名人</string> 69 </dict> 70 </array> 71 </array> 72 </plist>
对比上一次演练中我们使用的plist文件,我们多引入了一层array定义,这样就把原有的一维数据序列,调整成二维序列了。怎么样?还不错吧。:]
三. 数据加载处理
1. 在导航区域,点击打开“JOYTableViewController.m”文件;
2. 在接口定义中将原来定义的数据名称由_userList改为_categoryList,如下所示:
1 @interface JOYTableViewController () { 2 @private 3 NSMutableArray *_categoryList; 4 }
3. 在viewDidLoad方法中调整数据加载部分进行调整,调整后的viewDidLoad方法如下所示:
1 - (void)viewDidLoad 2 { 3 [super viewDidLoad]; 4 5 // 设定pList文件路径 6 NSString *dataPath = [[NSBundle mainBundle]pathForResource:@"FocusUsers.plist" ofType:nil]; 7 // 填充数组内容 8 NSMutableArray *array = [NSMutableArray arrayWithContentsOfFile:dataPath]; 9 10 _categoryList = [[NSMutableArray alloc]init]; 11 for (NSDictionary *item in array) { 12 NSMutableArray *userList = [[NSMutableArray alloc]init]; 13 14 // 针对每个分类项,创建一个用户数组 15 for (NSDictionary *users in item) { 16 JOYFocusUser *user = [[JOYFocusUser alloc]initWithItem:users]; 17 [userList addObject:user]; 18 } 19 20 // 将用户数组项目添加到分类数组中 21 [_categoryList addObject:userList]; 22 } 23 }
4. 找到numberOfSectionsInTableView方法,将其中代码进行修改,如下所示:
1 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 2 { 3 return [_categoryList count]; 4 }
在本演练数据中,我们一共包含三个分类,所以在此返回结果是3。
5. 找到
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
方法,将其中代码进行修改,如下所示:
1 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 2 { 3 return [[_categoryList objectAtIndex:section]count]; 4 }
这里的代码稍微有些别扭,我们会在后续调整一下,让它更好读一些,在此先简单解释一下。
从plist文件的结构中,我们不难发现[_categoryList objectAtIndex:section]对应的是指定区段数的一个用户数组,假如我们把这个理解为“userList”,则这条语句可以看成是return [userList count],返回的是指定区段的用户数组的个数。
6. 找到
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
方法,将其中解析数据部分代码进行修改,修改后的方法如下所示:
1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 static NSString *CellIdentifier = @"Cell"; 4 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 5 6 // Configure the cell... 7 // 实例化单元格对象 8 if (cell == nil) { 9 cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 10 } 11 12 NSMutableArray *array = [_categoryList objectAtIndex:[indexPath section]]; 13 JOYFocusUser *user = [array objectAtIndex:[indexPath row]]; 14 15 // 设置单元格文本 16 // NSDictionary *item = [_userList objectAtIndex:indexPath.row]; 17 [cell.textLabel setText:[user userName]]; 18 // 设定字体 19 [cell.textLabel setFont:[UIFont fontWithName:@"Helvetica" size:16.0f]]; 20 // 改变字体颜色 21 [cell.textLabel setTextColor:[UIColor orangeColor]]; 22 // 调整文本居中对齐 23 [cell.textLabel setTextAlignment:UITextAlignmentCenter]; 24 25 // 显示头像 26 [cell.imageView setImage:[user image]]; 27 28 return cell; 29 }
为了便于大家的阅读,我把上一次演练中的代码注释了,这样方便我们更加直观地看出到底做了哪些修改。
7. 运行一下,看看效果:]
天啊,忙乎了一溜够,竟然和上次演练之后没有发生任何的变化,这⋯⋯
不要着急,现在激动人心的时刻就要到了,嘿嘿。
8. 找到numberOfSectionsInTableView方法,在它的下面插入一个
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 方法
并增加一条语句,如下所示:
1 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 2 // 获取指定区段的用户数组 3 NSMutableArray *userList = [_categoryList objectAtIndex:section]; 4 // 获取数组中第一个用户记录 5 JOYFocusUser *user = [userList objectAtIndex:0]; 6 // 返回该用户的分类名称 7 return user.categoryName; 8 }
相关语句到底干了什么,见注释即可,我就不再啰嗦了。
9. 运行一下,如下图所示:
哈哈,怎么样?不复杂吧。
小提示:可能有不少从其他平台,例如Eclipse或者MS VS等转过来的朋友会向我当初一样有一些类似的疑问:这个方法是怎么加入的呢?我怎么知道系统预设了这个方法呢?有没有某个菜单命令能够弹出一个对话框,让我选择具体要重载哪个方法呢?
答案是:直接输入。呵呵,刚开始使用Xcode时,我也有些不习惯,不过后来发现,Xcode提供的智能输入提示非常友好,在程序开发时非常高效地,程序员不用时不时地因为一些小事,就不得不把手从键盘移到鼠标上,去做一些无聊的事情。在Xcode中,编写某一个类的代码时,几乎可以不用使用鼠标,就完成所有的编码工作。
好了,言归正传,在上述的代码中,某些地方有些取巧,如果你只是开发这么一个简单的应用,已经足够了。不过如果考虑到以后系统的维护和扩充,我们还是要尽量将数据和界面分开。
四. 使用分类数据模型
1. 在导航区域,点击并打开“JOYFocusUser.h”文件,在文件末尾增加如下代码:
1 @interface JOYCategory : NSObject 2 3 @property (strong, nonatomic) NSString *categoryName; 4 @property (strong, nonatomic) NSMutableArray *userList; 5 6 // 使用用户列表实例化对象 7 - (id)initWithArray:(NSMutableArray *)userList; 8 9 @end
在此,我们新定义了一个JOYCategory的类,用于按类别存储用户列表;
2. 点击打开“JOYFocusUser.m”文件,在文件的末尾增加如下代码:
1 @implementation JOYCategory 2 @synthesize categoryName = _categoryName; 3 @synthesize userList = _userList; 4 5 - (id)initWithArray:(NSMutableArray *)userList { 6 7 self = [super init]; 8 if (self) { 9 NSMutableArray *list = [[NSMutableArray alloc]init]; 10 for (NSDictionary *item in userList) { 11 JOYFocusUser *user = [[JOYFocusUser alloc]initWithItem:item]; 12 [list addObject:user]; 13 } 14 15 JOYFocusUser *user = [list objectAtIndex:0]; 16 _categoryName = user.categoryName; 17 _userList = list; 18 } 19 return self; 20 } 21 22 @end
3. 在导航区域,点击打开“JOYTableViewController.m”文件;
4. 对viewDidLoad中的数据加载部分的代码调整如下:
1 - (void)viewDidLoad 2 { 3 [super viewDidLoad]; 4 5 // 设定pList文件路径 6 NSString *dataPath = [[NSBundle mainBundle]pathForResource:@"FocusUsers.plist" ofType:nil]; 7 // 填充数组内容 8 NSMutableArray *array = [NSMutableArray arrayWithContentsOfFile:dataPath]; 9 10 _categoryList = [[NSMutableArray alloc]init]; 11 // for (NSDictionary *item in array) { 12 // NSMutableArray *userList = [[NSMutableArray alloc]init]; 13 // 14 // // 针对每个分类项,创建一个用户数组 15 // for (NSDictionary *users in item) { 16 // JOYFocusUser *user = [[JOYFocusUser alloc]initWithItem:users]; 17 // [userList addObject:user]; 18 // } 19 // 20 // // 将用户数组项目添加到分类数组中 21 // [_categoryList addObject:userList]; 22 // } 23 for (NSMutableArray *item in array) { 24 JOYCategory *category = [[JOYCategory alloc]initWithArray:item]; 25 [_categoryList addObject:category]; 26 } 27 }
5. 在
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section方法中做如下调整:
1 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 2 // // 获取指定区段的用户数组 3 // NSMutableArray *userList = [_categoryList objectAtIndex:section]; 4 // // 获取数组中第一个用户记录 5 // JOYFocusUser *user = [userList objectAtIndex:0]; 6 // // 返回该用户的分类名称 7 // return user.categoryName; 8 JOYCategory *category = [_categoryList objectAtIndex:section]; 9 return [category categoryName]; 10 }
6. 在
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section方法中做如下调整:
1 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 2 { 3 // return [[_categoryList objectAtIndex:section]count]; 4 JOYCategory *category = [_categoryList objectAtIndex:section]; 5 return [category.userList count]; 6 }
7. 在
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法中做如下调整:
1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 static NSString *CellIdentifier = @"Cell"; 4 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 5 6 // Configure the cell... 7 // 实例化单元格对象 8 if (cell == nil) { 9 cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 10 } 11 12 // NSMutableArray *array = [_categoryList objectAtIndex:[indexPath section]]; 13 // JOYFocusUser *user = [array objectAtIndex:[indexPath row]]; 14 JOYCategory *category = [_categoryList objectAtIndex:[indexPath section]]; 15 JOYFocusUser *user = [category.userList objectAtIndex:[indexPath row]]; 16 17 // 设置单元格文本 18 // NSDictionary *item = [_userList objectAtIndex:indexPath.row]; 19 [cell.textLabel setText:[user userName]]; 20 // 设定字体 21 [cell.textLabel setFont:[UIFont fontWithName:@"Helvetica" size:16.0f]]; 22 // 改变字体颜色 23 [cell.textLabel setTextColor:[UIColor orangeColor]]; 24 // 调整文本居中对齐 25 [cell.textLabel setTextAlignment:UITextAlignmentCenter]; 26 27 // 显示头像 28 [cell.imageView setImage:[user image]]; 29 30 return cell; 31 }
小提示:为了便于大家的阅读,我把前面演练中的代码注释了,这样方便我们更加直观地看出到底做了哪些修改。由于我把每一个方法的完成代码都复制过来了,其实我们在每个方法中所作的修改只是一两条语句而已。
8. 运行看一下效果,和前面演练完的效果并没有太大的变化,不过现在的代码的可读性已经有所提高了:]
五. 小结
首先要向大家表示歉意,因为本人的博客只是利用业余时间编写的,更新速度有些缓慢,还望大家见谅。
本演练源程序下载地址:JoyiOSMyFocus3.zip
到目前位置,我们对UITableView的数据加载、显示、分组已经做了一个初步的介绍。在后面的演练中,我们将针对自定义单元格、表格数据操作以及自定义视图进行介绍,同时引入一个iOS应用中非常常见的Navigation控件。计划还需要两~三章的内容可以完成,敬请期待。