标签:
1 tableView的编辑模式
1.1 问题
表视图可以进入编辑模式,当进入编辑模式就可以进行删除、插入、移动单元等操作,本案例还是使用联系人界面学习如何进入编辑模式,以及进入编辑模式之后的删除、插入、移动等操作,如图-1所示:
图-1
1.2 方案
首先还是创建一个带导航的TRContactTableViewController对象做为根视图控制器。
其次创建一个TRContact类用于管理联系人信息,有两个NSString类型的属性分别为name和phoneNumber,本案例为了学习方便创建一组联系人信息直接使用。将创建好的联系人信息直接加载到tableView中显示。
然后让表视图进入编辑模式,进入编辑模式的方法有两种,一种是使用导航栏的edit按钮,另一种是设置tableView的editing属性进入编辑模式。
最后通过实现UITableViewDataSource协议的方法实现单元格的删除、插入和移动。
1.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目,加载数据
在已建好的Xcode项目中创建一个表视图控制器类TRContactTableViewController,并且定义一个用来管理联系人的NSMutableArray类型的公开属性contacts用来存储表视图需要展示的数据,代码如下所示:
- @interface TRContactTableViewController : UITableViewController
- @property (nonatomic, strong) NSMutableArray *contacts;
- @end
其次在TRContact类里面定义两个属性name和phoneNumber,并实现一个静态方法,返回一组联系人信息,代码如下所示:
- @interface TRContact : NSObject
- @property (nonatomic, strong) NSString *name;
- @property (nonatomic, strong) NSString *phoneNumber;
- + (NSArray *)demoData;
- @end
- @implementation TRContact
- + (NSArray *)demoData
- {
- TRContact *c1 = [[TRContact alloc]init];
- c1.name = @"张三";
- c1.phoneNumber = @"18610001000";
- TRContact *c2 = [[TRContact alloc]init];
- c2.name = @"李四";
- c2.phoneNumber = @"18610001003";
- TRContact *c3 = [[TRContact alloc]init];
- c3.name = @"王五";
- c3.phoneNumber = @"18610001001";
- return @[c1, c2, c3];
- }
- @end
然后让TRContactTableViewController展示联系人信息,代码如下所示:
- -(NSInteger)tableView:(UITableView *)tableView
- numberOfRowsInSection:(NSInteger)section
- {
- return self.contacts.count;
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- }
- TRContact *contact = self.contacts[indexPath.row];
- cell.textLabel.text = contact.name;
- return cell;
- }
最后在TRAppDelegate的程序入口方法里面创建一个带有导航的表视图控制器做为根视图控制器,并给contactTVC的contacts属性赋值,代码如下所示:
- -(BOOL)application:(UIApplication *)application
- didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- self.window.backgroundColor = [UIColor whiteColor];
- TRContactTableViewController *contactTVC = [[TRContactTableViewController alloc]initWithNibName:@"TRContactTableViewController" bundle:nil];
- contactTVC.contacts = [[TRContact demoData] mutableCopy];
- UINavigationController *navi = [[UINavigationController alloc]initWithRootViewController:contactTVC];
- self.window.rootViewController = navi;
- [self.window makeKeyAndVisible];
- return YES;
- }
步骤二:进入编辑模式
进入编辑模式的方法有两种,一种是直接使用导航栏的edit按钮,该按钮是由系统直接提供使用,点击edit按钮能够直接进入编辑模式,再按一次就会退出编辑模式,代码如下所示:
- self.navigationItem.rightBarButtonItem = self.editButtonItem;
另一种进入编辑模式的方式是修改tableView的editing属性,该属性是一个BOOL类型,默认值是NO,这里给导航栏添加一个左按钮,通过点击左按钮修改editing属性的值进入和退出编辑模式,代码如下所示:
- self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(editTableView:)];
实现editTableView:方法,通过setEditing:animated:方法修改editing属性的值,根据是否进入编辑模式,按钮的标题也随着改变,代码如下所示:
- - (void)editTableView:(UIBarButtonItem *)button
- {
- [self.tableView setEditing:!self.tableView.editing animated:YES];
- if(self.tableView.editing){
- button.title = @"完成";
- }else{
- button.title = @"编辑";
- }
- }
运行程序,界面完成效果如图-2所示:
图-2
步骤三:实现删除和插入行
首先需要确定哪些行可以进入编辑模式,默认情况下所有行都是可以进入编辑模式的,通过实现协议方法tableView:canEditRowAtIndexPath告诉tableView,这里禁止第一行进入编辑模式,代码如下所示:
- -(BOOL)tableView:(UITableView *)tableView
- canEditRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if(indexPath.row == 0) return NO;
- return YES;
- }
然后选择编辑样式,通过实现协议方法tableView:editingStyleForRowAtIndexPath:告诉tableView编辑样式,该方法的返回值是一个UITableViewCellEditingStyle枚举类型,编辑样式只有两种删除和插入,这里让最后一行实现插入操作,其他行实现删除操作,代码如下所示:
- -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView
- editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if(indexPath.row == self.contacts.count - 1){
- return UITableViewCellEditingStyleInsert;
- }
- return UITableViewCellEditingStyleDelete;
- }
当真正执行删除或插入某一行时,会调用协议方法tableView:commitEditingStyle: forRowAtIndexPath:,因此将删除或者插入的操作代码都写在该方法里面。
如果执行的是删除操作则先找到该行对应的数据,其次从数据源数组中删除相应的数据对象,然后删除tableView中对应的行,删除行调用方法deleteRowsAtIndexPaths:withRowAnimation:,indexPath参数是删除行的路径,rowAnimation参数是删除行的动画样式,代码如下所示:
- -(void)tableView:(UITableView *)tableView
- commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
- forRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if (editingStyle == UITableViewCellEditingStyleDelete) {
- [self.contacts removeObjectAtIndex:indexPath.row];
- [tableView deleteRowsAtIndexPaths:@[indexPath]
- withRowAnimation:UITableViewRowAnimationFade];
- }
- }
如果执行的是插入操作则先创建需要增加的数据对象,其次将数据对象添加到数据源数组中,然后在tableView中找到需要插入行的位置indexPath,最后调用方法insertRowsAtIndexPaths:withRowAnimation:插入行,indexPaths参数需要一个数组类型,因此将插入位置放进数组进行传递,rowAnimation参数是插入行的动画样式,代码如下所示:
- -(void)tableView:(UITableView *)tableView
- commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
- forRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if (editingStyle == UITableViewCellEditingStyleDelete) {
- [self.contacts removeObjectAtIndex:indexPath.row];
- [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
- }else if (editingStyle == UITableViewCellEditingStyleInsert) {
- TRContact *contact = [[TRContact alloc]init];
- contact.name = @"陈七";
- contact.phoneNumber = @"18612345678";
- [self.contacts addObject:contact];
- NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.contacts.count - 1 inSection:0];
- [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
- }
- }
运行程序点击编辑按钮,tableView进入编辑模式,如图-3所示:
图-3
由图-3中可以看见,第一行被禁止编辑,第二行是删除编辑样式(红色圆圈),第三行是插入编辑样式(绿色圆圈),点击第二行前面的红圈,则在该行的尾部会出现一个Delete按钮,如图-4所示:
图-4
点击Delete按钮,则该行会被删除,第三行会变成第二行,如图-5所示:
图-5
再点击此时第二行前面的绿色按钮,则在最后一行后面直接插入一行新的单元格,显示一个新的数据,第二行的编辑样式会变成删除,如图-6所示:
图-6
步骤四:实现移动行
当tableView进入编辑模式之后,默认每一行都是可以移动,每一行尾部有一个图标为三行灰色横线的按钮,就是表示该行可以移动,如图-7所示:
图-7
由图中可见,除了第一行,另外两行都是可以移动的,因为第一行的编辑模式被禁止了。另外还可以通过实现协议方法tableView:canMoveRowAtIndexPath:来确定哪些行可以移动,代码如下所示:
- -(BOOL)tableView:(UITableView *)tableView
- canMoveRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if(indexPath.row == 2) return NO;
- return YES;
- }
运行程序,可见第三行的移动按钮消失了,如图-8所示:
图-8
按住移动按钮则可以移动该行到任意位置,界面上显示的数据会重新排列,最后需要实现协议方法tableView:moveRowAtIndexPath: toIndexPath,将数据源数组里面的数据也进行重新排列,代码如下所示:
- - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
- {
- TRContact *contact = self.contacts[fromIndexPath.row];
- [self.contacts removeObjectAtIndex:fromIndexPath.row];
- [self.contacts insertObject:contact atIndex:toIndexPath.row];
- }
1.4 完整代码
本案例中,TRAppDelegate.m文件中的完整代码如下所示:
- #import "TRAppDelegate.h"
- #import "TRContactTableViewController.h"
- #import "TRContact.h"
- @implementation TRAppDelegate
- -(BOOL)application:(UIApplication *)application
- didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- self.window.backgroundColor = [UIColor whiteColor];
- TRContactTableViewController *contactTVC = [[TRContactTableViewController alloc]initWithNibName:@"TRContactTableViewController" bundle:nil];
- contactTVC.contacts = [[TRContact demoData] mutableCopy];
- UINavigationController *navi = [[UINavigationController alloc]initWithRootViewController:contactTVC];
- self.window.rootViewController = navi;
- [self.window makeKeyAndVisible];
- return YES;
- }
- @end
本案例中,TRMyFirstViewController.h文件中的完整代码如下所示:
- #import<UIKit/UIKit.h>
- @interface TRContactTableViewController : UITableViewController
- @property (nonatomic, strong) NSMutableArray *contacts;
- @end
本案例中,TRMyFirstViewController.m文件中的完整代码如下所示:
- #import "TRContactTableViewController.h"
- #import "TRContact.h"
- @implementation TRContactTableViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.navigationItem.rightBarButtonItem = self.editButtonItem;
- self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(editTableView:)];
- }
- - (void)editTableView:(UIBarButtonItem *)button
- {
- [self.tableView setEditing:!self.tableView.editing animated:YES];
- if(self.tableView.editing){
- button.title = @"完成";
- }else{
- button.title = @"编辑";
- }
- }
- -(NSInteger)tableView:(UITableView *)tableView
- numberOfRowsInSection:(NSInteger)section
- {
- return self.contacts.count;
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- }
- TRContact *contact = self.contacts[indexPath.row];
- cell.textLabel.text = contact.name;
- return cell;
- }
- -(BOOL)tableView:(UITableView *)tableView
- canEditRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if(indexPath.row == 0) return NO;
- return YES;
- }
- -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView
- editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if(indexPath.row == self.contacts.count - 1) return UITableViewCellEditingStyleInsert;
- return UITableViewCellEditingStyleDelete;
- }
- -(void)tableView:(UITableView *)tableView
- commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
- forRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if (editingStyle == UITableViewCellEditingStyleDelete) {
- [self.contacts removeObjectAtIndex:indexPath.row];
- [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
- }
- else if (editingStyle == UITableViewCellEditingStyleInsert) {
- TRContact *contact = [[TRContact alloc]init];
- contact.name = @"陈七";
- contact.phoneNumber = @"18612345678";
- [self.contacts addObject:contact];
- NSIndexPath *indexPath = [NSIndexPathindexPathForRow:self.contacts.count-1 inSection:0];
- [tableView insertRowsAtIndexPaths:@[indexPath]
- withRowAnimation:UITableViewRowAnimationAutomatic];
- }
- }
- -(void)tableView:(UITableView *)tableView
- moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
- toIndexPath:(NSIndexPath *)toIndexPath
- {
- TRContact *contact = self.contacts[fromIndexPath.row];
- [self.contacts removeObjectAtIndex:fromIndexPath.row];
- [self.contacts insertObject:contact atIndex:toIndexPath.row];
- }
- -(BOOL)tableView:(UITableView *)tableView
- canMoveRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if(indexPath.row == 2) return NO;
- return YES;
- }
- @end
本案例中,TRContact.h文件中的完整代码如下所示:
- #import<Foundation/Foundation.h>
- @interface TRContact : NSObject
- @property (nonatomic, strong) NSString *name;
- @property (nonatomic, strong) NSString *phoneNumber;
- + (NSArray *)demoData;
- @end
本案例中,TRContact.m文件中的完整代码如下所示:
- #import "TRContact.h"
- @implementation TRContact
- + (NSArray *)demoData
- {
- TRContact *c1 = [[TRContact alloc]init];
- c1.name = @"张三";
- c1.phoneNumber = @"18610001000";
- TRContact *c2 = [[TRContact alloc]init];
- c2.name = @"李四";
- c2.phoneNumber = @"18610001003";
- TRContact *c3 = [[TRContact alloc]init];
- c3.name = @"王五";
- c3.phoneNumber = @"18610001001";
- return @[c1, c2, c3];
- }
- @end
2 展示4种不同的系统视图
2.1 问题
UITableViewCell是UIView的子类,内部由两大视图组成,内容视图contentView和辅助视图accessoryView。
contentView由textLabel、detailTextLabel以及imageView组成。
accessoryView默认情况下为空,在编辑模式下会隐藏起来,本案例将在上一个案例的基础上展示四种不同的辅助视图样式。
2.2 方案
辅助视图的类型accessoryType是一个UITableViewCellAccessoryType的枚举类型,提供了四种系统样式,分别为:
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryCheckmark
UITableViewCellAccessoryDetailButton
本案例直接在上一个案例的基础上实现,在协议方法 cellForRowAtIndexPath里面设置辅助视图的样式,查看不同的效果。
2.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:设置辅助视图的样式
直接在TRContactTableViewController.m文件中的协议方法tableView: cellForRowAtIndexPath里面,通过设置cell的accessoryType属性来辅助视图的样式,先设置成UITableViewCellAccessoryDisclosureIndicator样式,代码如下所示:
- cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
运行程序,实现效果如图-9所示:
图-9
然后设置成UITableViewCellAccessoryDetailDisclosureButton样式,代码如下所示:
- cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
运行程序,实现效果如图-10所示:
图-10
再设置成UITableViewCellAccessoryCheckmark样式,代码如下所示:
- cell.accessoryType = UITableViewCellAccessoryCheckmark;
运行程序,实现效果如图-11所示:
图-11
最后设置成UITableViewCellAccessoryDetailButton样式,代码如下所示:
- cell.accessoryType = UITableViewCellAccessoryDetailButton;
运行程序,实现效果如图-12所示:
图-12
2.4 完整代码
本案例中,TRContactTableViewController.m文件中的cellForRowAtIndexPath方法中的完整代码如下所示:
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- }
- TRContact *contact = self.contacts[indexPath.row];
- cell.textLabel.text = contact.name;
- cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
- return cell;
- }
3 展示一个Cell的不同事件方法
3.1 问题
上一个案例展示四种辅助视图的样式,四种样式都不同的应用场景,本案例将学习四种辅助视图的样式不同应用场景。
3.2 方案
UITableViewCellAccessoryDisclosureIndicator样式在界面上是一个“>”符号,通常用于提示用户点击此Cell有更详细的信息,所以使用此样式时通常都会实现协议方法tableView:didSelectRowAtIndexPath:;
UITableViewCellAccessoryDetailDisclosureButton样式在界面上是一个“i”按钮和一个“>”符号,通常用于提示用户点击此按钮(不是Cell)会有更详细的信息,会调用协议方法tableView:accessoryButtonTappedForRowWithIndexPath:来展示详细信息,这里需要特别注意点击cell和点击i按钮调用的方法是不同的;
UITableViewCellAccessoryCheckmark样式在界面上是一个“√”通常用于做标记;
UITableViewCellAccessoryDetailButton样式在界面上是一个“i”按钮,通常用于提示用户点击此按钮会有详细信息,同样会通过调用协议方法tableView:accessoryButtonTappedForRowWithIndexPath:来展示消息信息。
本案例在上一个案例的基础上通过实现协议方法didSelectRowAtIndexPath:和accessoryButtonTappedForRowWithIndexPath:来响应不同的用户选择。
3.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:设置辅助视图样式
本案例将辅助视图的样式设置为UITableViewCellAccessoryDetailButton,代码如下所示:
- cell.accessoryType = UITableViewCellAccessoryDetailButton;
步骤二:实现点击辅助视图按钮时调用的协议方法
点击按钮时,会自动调用UITableViewDelegate协议中的协议方法tableView:accessoryButtonTappedForRowWithIndexPath:,本案例在该方法里面输出一句话,模拟用户查看详细信息,代码如下所示:
- -(void)tableView:(UITableView *)tableView
- accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
- {
- TRContact *contact = self.contacts[indexPath.row];
- NSLog(@"用户点击的是Cell上的按钮而不是Cell本身,他可能想查看%@的详细信息", contact.name);
- }
运行程序,当点击辅助视图按钮时,可见在控制台输出“用户点击的是Cell上的按钮而不是Cell本身……“,以上方法被调用。
步骤三:实现点击cell时调用的协议方法
点击cell时,会自动调用UITableViewDelegate协议中的协议方法tableView:didSelectRowAtIndexPath:,本案例在该方法里面输出一句话,模拟用户查看详细信息,同时将辅助视图的样式做修改,代码如下所示:
- - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- {
- TRContact *contact = self.contacts[indexPath.row];
- NSLog(@"用户点击了此Cell本身,他想直接给%@打电话", contact.name);
- UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
- if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
- cell.accessoryType = UITableViewCellAccessoryDetailButton;
- }else{
- cell.accessoryType = UITableViewCellAccessoryCheckmark;
- }
- }
运行程序,当cell时,可见在控制台输出“用户点击了此Cell本身……”,以上方法被调用。
3.4 完整代码
本案例中,TRContactTableViewController.m文件中的完整代码如下所示:
4 展示自定义辅助视图
4.1 问题
辅助视图除了可以使用系统提供的四种样式,还可以自定义辅助视图根据不同需求展示不同的界面,本案例将学习如何自定义辅助视图,如图-13所示:
图-13
4.2 方案
首先自定义一个视图,根据不同的需求展示不同的界面,然后让cell.accessoryView指向自定义的视图即可。
4.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建表视图项目
首先使用Xcode创建一个表视图项目,在TRMyTableViewController.m文件中实现协议方法告诉tableView展示多少分区和多少行,本案例展示两个分区,第一个分区有两行单元格,第二个分区有三行单元格,代码如下所示:
- -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- {
- return 2;
- }
- -(NSInteger)tableView:(UITableView *)tableView
- numberOfRowsInSection:(NSInteger)section
- {
- if(section==0) return 2;
- else if(section==1) return 3;
- return 0;
- }
然后在cellForRowAtIndexPath:方法里面创建cell,代码如下所示:
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- return cell;
- }
步骤二:自定义辅助视图
本案例中让表视图的每一行展示几种不同的自定义辅助视图,所以根据每个cell不同的路径显示不一样的辅助视图,首先自定义第一个分区第一行单元格的辅助视图,展示一个UISwitch开关,代码如下所示:
- if(indexPath.section==0 && indexPath.row==0){
- cell.textLabel.text = @"蓝牙";
- UISwitch *blueSwitch = [[UISwitch alloc]init];
- cell.accessoryView = blueSwitch;
- }
然后自定义第一个分区第二行单元格的辅助视图,展示一个UIButton按钮,代码如下所示:
- if(indexPath.section==0 && indexPath.row==0){
- cell.textLabel.text = @"蓝牙";
- UISwitch *blueSwitch = [[UISwitch alloc]init];
- cell.accessoryView = blueSwitch;
- }else if(indexPath.section==0 && indexPath.row==1){
- cell.textLabel.text = @"运营商";
- UIButton *serviceButton = [UIButton buttonWithType:UIButtonTypeSystem];
- serviceButton.frame = CGRectMake(0, 0, 44, 44);
- [serviceButton setTitle:@"选择" forState:UIControlStateNormal];
- [serviceButton addTarget:self
- action:@selector(selectService:)
- forControlEvents:UIControlEventTouchUpInside];
- cell.accessoryView = serviceButton;
- }
第一个分区的辅助视图就定义完成了,运行程序,展示界面效果如图-14所示:
图-14
然后再自定义第二个分区的辅助视图,第一行单元格的辅助视图展示一个UITextField文本输入框,代码如下所示:
- if(indexPath.section==1 && indexPath.row==0){
- cell.textLabel.text = @"姓名:";
-
- UITextField *inputBox = [[UITextField alloc]initWithFrame:CGRectMake(0, 2, 200, 35)];
- [inputBox setBackgroundColor:[UIColor lightGrayColor]];
- cell.accessoryView = inputBox;
- }
最后自定义第二个分区第二行单元格的辅助视图,展示一个UILabel和一个UIStepper控件,代码如下所示:
- if(indexPath.section==1 && indexPath.row==0){
- cell.textLabel.text = @"姓名:";
- UITextField *inputBox = [[UITextField alloc]initWithFrame:CGRectMake(0, 2, 200, 35)];
- [inputBox setBackgroundColor:[UIColor lightGrayColor]];
- cell.accessoryView = inputBox;
- }elseif(indexPath.section==1 &&indexPath.row==1){
- cell.textLabel.text = @"次数:";
- UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 200, 44)];
- UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(15, 5, 20, 34)];
- label.text = @"0";
- label.textAlignment = NSTextAlignmentCenter;
- UIStepper *stepper = [[UIStepper alloc]initWithFrame:CGRectMake(80, 5, 160, 34)];
- [view addSubview:label];
- [view addSubview:stepper];
- cell.accessoryView = view;
- }else{
- cell.textLabel.text = @"hello.....";
- }
第二个分区的辅助视图就定义完成了,运行程序,展示界面效果如图-15所示:
图-15
4.4 完整代码
5 自定义ContentView的内容,展示当前计算机语言排名
5.1 问题
上一个案例学习了如何自定义辅助视图,本案例将学习如何自定义内容视图contentView,展示TIOBE计算机语言排行榜,如图-16所示:
图-16
5.2 方案
contentView中的子视图有三个textLabel,detailTextLabel和imageView,如果不进行赋值,这三个子视图都是nil。
这三个子视图都可以进行自定义,步骤如下:
首先根据不同的界面需求分别自定义textLabel,detailTextLabel和imageView;
然后分别将自定义好的三个子视图添加到contentView中即可。
5.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建表视图项目
首先使用Xcode创建一个表视图项目,在TRLanguageTableViewController.m文件中定义一个用于保存数据源的NSArray类型的属性,并且实现协议方法告诉tableView展示多少行,代码如下所示:
- @interface TRLanguageTableViewController ()
- @property (nonatomic, strong) NSArray *language;
- @end
- - (NSArray *)language
- {
- return @[@"C", @"Java", @"Objective-C", @"C++", @"C#", @"Basic", @"PHP", @"Python", @"Javascript", @"VB.Net", @"Transact-SQL", @"Perl", @"Ruby", @"ActionScript", @"F#", @"Lisp", @"Delphi/Pascal"];
- }
- -(NSInteger)tableView:(UITableView *)tableView
- numberOfRowsInSection:(NSInteger)section
- {
- }
步骤二:创建cell,并且自定义contentView
在协议方法cellForRowAtIndexPath:里面创建cell对象,代码如下所示:
- -(UITableViewCell *)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- }
- return cell;
- }
然后在以上方法中自定义cell的内容视图,由于cell是重用的,所以只用在第一次新创建cell对象的时候自定义好contentView即可,也就是将自定义内容视图的相关代码写在if(cell==nil)判断语句里面。
本案例的contentView里面是一个自定义的UILabel对象,由于每一行UILabel对象显示的文本内容不同,所以UILabel对象的定义应该在if(cell==nil)判断语句的前面,UILabel对象的创建(获取)和样式设置在if(cell==nil)判断语句里面,if(cell==nil)判断语句后面才是UILabel对象text属性的设置,代码如下所示:
- -(UITableViewCell *)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- UILabel *label = nil;
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- label = [[UILabel alloc]init];
- label.frame = CGRectMake(0, 0, 320, 44);
- label.textColor = [UIColor lightGrayColor];
- label.font = [UIFont italicSystemFontOfSize:18];
- label.textAlignment = NSTextAlignmentCenter;
- label.shadowColor = [UIColor blackColor];
- label.shadowOffset = CGSizeMake(1, 1);
- [cell.contentView addSubview:label];
- label.tag = 1;
- }else {
- label = (UILabel*)[cell.contentView viewWithTag:1];
- }
- label.text = self.language[indexPath.row];
- return cell;
- }
5.4 完整代码
本案例中,TRLanguageTableViewController.m文件中的完整代码如下所示:
- #import "TRLanguageTableViewController.h"
- @interface TRLanguageTableViewController ()
- @property (nonatomic, strong) NSArray *language;
- @end
- @implementation TRLanguageTableViewController
- - (NSArray *)language
- {
- return @[@"C", @"Java", @"Objective-C", @"C++", @"C#", @"Basic", @"PHP", @"Python", @"Javascript", @"VB.Net", @"Transact-SQL", @"Perl", @"Ruby", @"ActionScript", @"F#", @"Lisp", @"Delphi/Pascal"];
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.title = @"TIOBE";
- }
- -(NSInteger)tableView:(UITableView *)tableView
- numberOfRowsInSection:(NSInteger)section
- {
- return self.language.count;
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- UILabel *label = nil;
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- label = [[UILabel alloc]init];
- label.frame = CGRectMake(0, 0, 320, 44);
- label.textColor = [UIColor lightGrayColor];
- label.font = [UIFont italicSystemFontOfSize:18];
- label.textAlignment = NSTextAlignmentCenter;
- label.shadowColor = [UIColor blackColor];
- label.shadowOffset = CGSizeMake(1, 1);
- [cell.contentView addSubview:label];
- label.tag = 1;
- }else {
- label = (UILabel*)[cell.contentView viewWithTag:1];
- }
- label.text = self.language[indexPath.row];
- return cell;
- }
- @end
6 网易新闻项目的Cell自定义
6.1 问题
UITableViewCell类是表视图的标准Cell类,自定义Cell就是自己写一个Cell类继承至UITabelViewCell,然后在协议方法cellForRowAtIndexPath:里面创建cell对象时使用自定义的Cell类型并返回。
本案例将使用自定义cell的方式模拟实现一个网易新闻客户端的界面,实现效果如图-17所示:
图-17
6.2 方案
首先创建一个表视图控制器的项目,表视图控制器类命名为TRNewsTableViewController,该类有一个管理新闻数据的NSArray类型的属性news。
其次根据本案例的需求创建一个实体新闻类TRNews类,该类有四个属性分别为NSString类型的title(新闻标题)、NSString类型的content(新闻内容),NSUInteger类型的count(评论数)以及NSString类型的imageName(新闻图片名称),本案例中在该类中直接定义一个静态方法,用于创建一组新闻数据。在TRAppDelegate.m文件中使用该静态方法给TRNewsTableViewController的news属性赋值。
然后创建一个带有xib的TRNewsCell类,继承至UITabelViewCell,在xib文件中根据需要从对象库中拖放控件,本案例拖放一个UIImageView和三个UILabel对象。
最后在TRNewsTableViewController.m文件中实现协议方法,创建自定义类型的cell,并加载数据。
6.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建TRNewsTableViewController类
同以往的案例一样创建一个表视图控制类TRNewsTableViewController,并且定义一个NSArray类型的属性news用于管理新闻数据,代码如下所示:
- @interface TRNewsTableViewController : UITableViewController
- @property (nonatomic, strong) NSArray *news;
- @end
然后将本案例所需的图片素材拖放进项目。
步骤二:创建新闻实体类TRNews
创建一个TRNews类继承至NSObject,并且定义四个属性分别为NSString类型的title(新闻标题)、NSString类型的content(新闻内容),NSUInteger类型的count(评论数)以及NSString类型的imageName(新闻图片名称),代码如下所示:
- @interface TRNews : NSObject
- @property (nonatomic, strong) NSString *title;
- @property (nonatomic, strong) NSString *content;
- @property (nonatomic) NSUInteger count;
- @property (nonatomic, strong) NSString *imageName;
- @end
然后定义一个静态方法用于返回一组新闻数据,代码如下所示:
- + (NSArray *)demoData
- {
- TRNews *n1 = [[TRNews alloc]init];
- n1.title = @"四川青川县今晨发生4.8地震";
- n1.content = @"震源深度15千米;网友反映称成都、绵阳等地均有震感";
- n1.count = 2255;
- n1.imageName = @"Apple Tree.ico";
- TRNews *n2 = [[TRNews alloc]init];
- n2.title = @"2名夺刀少年遭多所高校\"哄抢\"";
- n2.content = @"继南昌大学、清华大学、北京理工大学与澳门科技大学加入";
- n2.count = 8000;
- n2.imageName = @"Bliss.ico";
- TRNews *n3 = [[TRNews alloc]init];
- n3.title = @"代码显示iOS8将可分屏多任务";
- n3.content = @"开发者:该代码支持利用1/2,1/4或3/4屏幕来显示应用";
- n3.count = 8000;
- n3.imageName = @"Flowers.ico";
- TRNews *n4 = [[TRNews alloc]init];
- n4.title = @"Swift语言估计下月进入TIOBE前20名";
- n4.content = @"据上市公司达内科技估计,2014年7月世界计算面语言排名中,Swift将出现在前20名";
- n4.count = 12000000;
- n4.imageName = @"Rain.ico";
- return @[n1, n2, n3, n4];
- }
最后在TRAppDelegate.m文件的程序入口方法里面给TRNewsTableViewController的news属性赋值,代码如下所示:
- -(BOOL)application:(UIApplication *)application
- didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- self.window.backgroundColor = [UIColor whiteColor];
- TRNewsTableViewController *newsTVC = [[TRNewsTableViewController alloc]initWithNibName:@"TRNewsTableViewController" bundle:nil];
- newsTVC.news = [TRNews demoData];
- UINavigationController *navi = [[UINavigationController alloc]initWithRootViewController:newsTVC];
- self.window.rootViewController = navi;
- [self.window makeKeyAndVisible];
- return YES;
- }
步骤三:创建TRNewsCell类
创建一个带有xib文件的TRNewsCell类,该类继承至UITableViewCell,如图-18所示:
图-18
然后选中xib文件,在右边栏的第五个检查器中将cell的高度设置为74,如图-19所示:
图-19
在xib界面上根据需求从对象库中拖放控件到contentView上,本案例拖放一个UIImageView对象用于显示新闻图片,在拖放三个UILabel对象分别用于显示新闻标题、新闻内容以及新闻评论数,xib界面效果如图-20所示:
图-20
最后以拉线的方式将xib中的各控件关联成TRNewsCell的公开属性,代码如下所示:
- @interface TRNewsCell : UITableViewCell
- @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
- @property (weak, nonatomic) IBOutlet UILabel *contentLabel;
- @property (weak, nonatomic) IBOutlet UILabel *countLabel;
- @property (weak, nonatomic) IBOutlet UIImageView *newsImageView;
- @end
步骤四:在TRNewsTableViewController中使用自定义cell
首先通过协议方法numberOfRowsInSection:告诉表视图需要显示的行数,代码如下所示:
- -(NSInteger)tableView:(UITableView *)tableView
- numberOfRowsInSection:(NSInteger)section
- {
- return self.news.count;
- }
然后先将自定义的TRNewsCell类进行注册,注册首先需要定义一个static类型的标示符,然后在viewDidLoad方法里面使用registerNib:forCellReuseIdentifier:进行注册,代码如下所示:
- static NSString *cellIdentifier = @"NewsCell";
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.title = @"网易新闻客户端";
- UINib *nib = [UINib nibWithNibName:@"TRNewsCell" bundle:nil];
- [self.tableView registerNib:nib forCellReuseIdentifier:cellIdentifier];
- }
最后在协议方法cellForRowAtIndexPath:方法里面创建自定义的TRNewsCell类型的对象cell,并对cell各属性进行赋值,当然不要忘记导入头文件TRNewsCell.h,代码如下所示:
- -(UITableViewCell *)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- TRNews *news = self.news[indexPath.row];
- TRNewsCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
- cell.titleLabel.text = news.title;
- cell.contentLabel.text = news.content;
- int x = news.count / 10000;
- cell.countLabel.text = [NSString stringWithFormat:@"跟帖:%i%@", x?x:news.count, x?@"万":@""];
- cell.newsImageView.image = [UIImage imageNamed:news.imageName];
- return cell;
- }
本案例中还需通过协议方法要告诉tableView每一行的显示高度,因为此时已经不再是默认的单元格高度,代码如下所示:
- -(CGFloat)tableView:(UITableView *)tableView
- heightForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- return 76;
- }
6.4 完整代码
本案例中,TRAppDelegate.m文件中的完整代码如下所示:
- #import "TRAppDelegate.h"
- #import "TRNewsTableViewController.h"
- #import "TRNews.h"
- @implementation TRAppDelegate
- -(BOOL)application:(UIApplication *)application
- didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- self.window.backgroundColor = [UIColor whiteColor];
- TRNewsTableViewController *newsTVC = [[TRNewsTableViewController alloc]initWithNibName:@"TRNewsTableViewController" bundle:nil];
- newsTVC.news = [TRNews demoData];
- UINavigationController *navi = [[UINavigationController alloc]initWithRootViewController:newsTVC];
- self.window.rootViewController = navi;
- [self.window makeKeyAndVisible];
- return YES;
- }
- @end
本案例中,TRNewsTableViewController.h文件中的完整代码如下所示:
- #import<UIKit/UIKit.h>
- @interface TRNewsTableViewController : UITableViewController
- @property (nonatomic, strong) NSArray *news;
- @end
本案例中,TRNewsTableViewController.m文件中的完整代码如下所示:
- #import "TRNewsTableViewController.h"
- #import "TRNews.h"
- #import "TRNewsCell.h"
- @implementation TRNewsTableViewController
- static NSString *cellIdentifier = @"NewsCell";
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.title = @"网易新闻客户端";
- UINib *nib = [UINib nibWithNibName:@"TRNewsCell" bundle:nil];
- [self.tableView registerNib:nib forCellReuseIdentifier:cellIdentifier];
- }
- -(NSInteger)tableView:(UITableView *)tableView
- numberOfRowsInSection:(NSInteger)section
- {
- return self.news.count;
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- TRNews *news = self.news[indexPath.row];
- TRNewsCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
- cell.titleLabel.text = news.title;
- cell.contentLabel.text = news.content;
- int x = news.count / 10000;
- cell.countLabel.text = [NSString stringWithFormat:@"跟帖:%i%@", x?x:news.count, x?@"万":@""];
- cell.newsImageView.image = [UIImage imageNamed:news.imageName];
- return cell;
- }
- -(CGFloat)tableView:(UITableView *)tableView
- heightForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- return 76;
- }
- @end
本案例中,TRNewsCell.h文件中的完整代码如下所示:
- #import<UIKit/UIKit.h>
- @interface TRNewsCell : UITableViewCell
- @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
- @property (weak, nonatomic) IBOutlet UILabel *contentLabel;
- @property (weak, nonatomic) IBOutlet UILabel *countLabel;
- @property (weak, nonatomic) IBOutlet UIImageView *newsImageView;
- @end
本案例中,TRNews.h文件中的完整代码如下所示:
- #import<Foundation/Foundation.h>
- @interface TRNews : NSObject
- @property (nonatomic, strong) NSString *title;
- @property (nonatomic, strong) NSString *content;
- @property (nonatomic) NSUInteger count;
- @property (nonatomic, strong) NSString *imageName;
- + (NSArray *)demoData;
- @end
本案例中,TRNews.m文件中的完整代码如下所示:
- #import "TRNews.h"
- @implementation TRNews
- + (NSArray *)demoData
- {
- TRNews *n1 = [[TRNews alloc]init];
- n1.title = @"四川青川县今晨发生4.8地震";
- n1.content = @"震源深度15千米;网友反映称成都、绵阳等地均有震感";
- n1.count = 2255;
- n1.imageName = @"Apple Tree.ico";
- TRNews *n2 = [[TRNews alloc]init];
- n2.title = @"2名夺刀少年遭多所高校\"哄抢\"";
- n2.content = @"继南昌大学、清华大学、北京理工大学与澳门科技大学加入";
- n2.count = 8000;
- n2.imageName = @"Bliss.ico";
- TRNews *n3 = [[TRNews alloc]init];
- n3.title = @"代码显示iOS8将可分屏多任务";
- n3.content = @"开发者:该代码支持利用1/2,1/4或3/4屏幕来显示应用";
- n3.count = 8000;
- n3.imageName = @"Flowers.ico";
- TRNews *n4 = [[TRNews alloc]init];
- n4.title = @"Swift语言估计下月进入TIOBE前20名";
- n4.content = @"据上市公司达内科技估计,2014年7月世界计算面语言排名中,Swift将出现在前20名";
- n4.count = 12000000;
- n4.imageName = @"Rain.ico";
- return @[n1, n2, n3, n4];
- }
- @end
表视图控制器(TableViewController)(二)
标签:
原文地址:http://www.cnblogs.com/52190112cn/p/5049347.html