本文转自:http://www.cocoachina.com/ios/20140922/9710.htmlhtml
在iOS开发中UITableView能够说是使用最普遍的控件,咱们平时使用的软件中处处均可以看到它的影子,相似于微信、QQ、新浪微博等软件基本上随处都是UITableView。固然它的普遍使用天然离不开它强大的功能,今天这篇文章将针对UITableView重点展开讨论。今天的主要内容包括:ios
1.基本介绍
2.数据源
3.代理
4.性能优化
5.UITableViewCell
6.经常使用操做
7.UITableViewController
8.MVC模式
基本介绍
UITableView有两种风格:UITableViewStylePlain和UITableViewStyleGrouped。这二者操做起来其实并无本质区别,只是后者按分组样式显示前者按照普通样式显示而已。你们先看一下二者的应用:
1>分组样式
2>不分组样式
你们能够看到在UITableView中数据只有行的概念,并无列的概念,由于在手机操做系统中显示多列是不利于操做的。UITableView中每行数据都是一个UITableViewCell,在这个控件中为了显示更多的信息,iOS已经在其内部设置好了多个子控件以供开发者使用。若是咱们查看UITableViewCell的声明文件能够发如今内部有一个UIView控件(contentView,做为其余元素的父控件)、两个UILable控件(textLabel、detailTextLabel)、一个UIImage控件(imageView),分别用于容器、显示内容、详情和图片。使用效果相似于微信、QQ信息列表:
固然,这些子控件并不必定要所有使用,具体操做时能够经过UITableViewCellStyle进行设置,具体每一个枚举表示的意思已经在代码中进行了注释:
- typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
- UITableViewCellStyleDefault,
- UITableViewCellStyleValue1,
- UITableViewCellStyleValue2,
- UITableViewCellStyleSubtitle
- };
数据源
因为iOS是遵循MVC模式设计的,不少操做都是经过代理和外界沟通的,但对于数据源控件除了代理还有一个数据源属性,经过它和外界进行数据交互。 对于UITableView设置完dataSource后须要实现UITableViewDataSource协议,在这个协议中定义了多种 数据操做方法,下面经过建立一个简单的联系人管理进行演示:
首先咱们须要建立一个联系人模型KCContact
KCContact.h
-
- #import
-
- @interface KCContact : NSObject
-
- #pragma mark 姓
- @property (nonatomic,copy) NSString *firstName;
- #pragma mark 名
- @property (nonatomic,copy) NSString *lastName;
- #pragma mark 手机号码
- @property (nonatomic,copy) NSString *phoneNumber;
-
- #pragma mark 带参数的构造函数
- -(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber;
-
- #pragma mark 取得姓名
- -(NSString *)getName;
-
-
- #pragma mark 带参数的静态对象初始化方法
- +(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber;
- @end
KCContact.m
-
- #import "KCContact.h"
-
- @implementation KCContact
-
- -(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber{
- if(self=[super init]){
- self.firstName=firstName;
- self.lastName=lastName;
- self.phoneNumber=phoneNumber;
- }
- return self;
- }
-
- -(NSString *)getName{
- return [NSString stringWithFormat:@"%@ %@",_lastName,_firstName];
- }
-
- +(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber{
- KCContact *contact1=[[KCContact alloc]initWithFirstName:firstName andLastName:lastName andPhoneNumber:phoneNumber];
- return contact1;
- }
-
- @end
为了演示分组显示咱们不妨将一组数据也抽象成模型KCContactGroup
KCContactGroup.h
-
- #import
- #import "KCContact.h"
-
- @interface KCContactGroup : NSObject
-
- #pragma mark 组名
- @property (nonatomic,copy) NSString *name;
-
- #pragma mark 分组描述
- @property (nonatomic,copy) NSString *detail;
-
- #pragma mark 联系人
- @property (nonatomic,strong) NSMutableArray *contacts;
-
- #pragma mark 带参数个构造函数
- -(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts;
-
- #pragma mark 静态初始化方法
- +(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts;
-
- @end
KCContactGroup.m
-
- #import "KCContactGroup.h"
-
- @implementation KCContactGroup
-
-
- -(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts{
- if (self=[super init]) {
- self.name=name;
- self.detail=detail;
- self.contacts=contacts;
- }
- return self;
- }
-
- +(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts{
- KCContactGroup *group1=[[KCContactGroup alloc]initWithName:name andDetail:detail andContacts:contacts];
- return group1;
- }
- @end
而后在viewDidLoad方法中建立一些模拟数据同时实现数据源协议方法:
KCMainViewController.m
-
- #import "KCMainViewController.h"
- #import "KCContact.h"
- #import "KCContactGroup.h"
-
- @interface KCMainViewController (){
- UITableView *_tableView;
- NSMutableArray *_contacts;
- }
-
- @end
-
- @implementation KCMainViewController
-
- - (void)viewDidLoad {
- [super viewDidLoad];
-
-
- [self initData];
-
-
- _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
-
-
- _tableView.dataSource=self;
-
- [self.view addSubview:_tableView];
- }
-
- #pragma mark 加载数据
- -(void)initData{
- _contacts=[[NSMutableArray alloc]init];
-
- KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
- KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
- KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
- [_contacts addObject:group1];
-
-
-
- KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"];
- KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"];
- KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"];
- KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]];
- [_contacts addObject:group2];
-
-
-
- KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"];
- KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"];
-
- KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]];
- [_contacts addObject:group3];
-
-
- KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"];
- KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"];
- KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"];
- KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"];
- KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"];
- KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]];
- [_contacts addObject:group4];
-
-
- KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"];
- KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"];
- KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"];
- KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]];
- [_contacts addObject:group5];
-
- }
-
- #pragma mark - 数据源方法
- #pragma mark 返回分组数
- -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
- NSLog(@"计算分组数");
- return _contacts.count;
- }
-
- #pragma mark 返回每组行数
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
- NSLog(@"计算每组(组%i)行数",section);
- KCContactGroup *group1=_contacts[section];
- return group1.contacts.count;
- }
-
- #pragma mark返回每行的单元格
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
-
- NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row);
- KCContactGroup *group=_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
- UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
- cell.textLabel.text=[contact getName];
- cell.detailTextLabel.text=contact.phoneNumber;
- return cell;
- }
-
- #pragma mark 返回每组头标题名称
- -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
- NSLog(@"生成组(组%i)名称",section);
- KCContactGroup *group=_contacts[section];
- return group.name;
- }
-
- #pragma mark 返回每组尾部说明
- -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
- NSLog(@"生成尾部(组%i)详情",section);
- KCContactGroup *group=_contacts[section];
- return group.detail;
- }
- @end
运行能够看到以下效果:
你们在使用iPhone通信录时会发现右侧能够按字母检索,使用起来很方便,其实这个功能使用UITableView实现很简单,只要实现数据源协议的一个方法,构建一个分组标题的数组便可实现。数组元素的内容和组标题内容未必彻底一致,UITableView是按照数组元素的索引和每组数据索引顺序来定位的而不是按内容查找。
- #pragma mark 返回每组标题索引
- -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
- NSLog(@"生成组索引");
- NSMutableArray *indexs=[[NSMutableArray alloc]init];
- for(KCContactGroup *group in _contacts){
- [indexs addObject:group.name];
- }
- return indexs;
- }
效果以下:
须要注意的是上面几个重点方法的执行顺序,请看下图:
值得指出的是生成单元格的方法并非一次所有调用,而是只会生产当前显示在界面上的单元格,当用户滚动操做时再显示其余单元格。
注意:随着咱们的应用愈来愈复杂,可能常常须要调试程序,在iOS中默认状况下不能定位到错误代码行,咱们能够经过以下设置让程序定位到出错代码行:Show the Breakpoint navigator—Add Exception breakpoint。
代理
上面咱们已经看到通信录的简单实现,可是咱们发现单元格高度、分组标题高度以及尾部说明的高度都须要调整,此时就须要使用代理方法。UITableView代理方法有不少,例如监听单元格显示周期、监听单元格选择编辑操做、设置是否高亮显示单元格、设置行高等。
1.设置行高
- #pragma mark - 代理方法
- #pragma mark 设置分组标题内容高度
- -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
- if(section==0){
- return 50;
- }
- return 40;
- }
-
- #pragma mark 设置每行高度(每行高度能够不同)
- -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
- return 45;
- }
-
- #pragma mark 设置尾部说明内容高度
- -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
- return 40;
- }
2.监听点击
在iOS中点击某联系我的就能够呼叫这个联系人,这时就须要监听点击操做,这里就不演示呼叫联系人操做了,咱们演示一下修改人员信息的操做。
KCMainViewContrller.m
-
- #import "KCMainViewController.h"
- #import "KCContact.h"
- #import "KCContactGroup.h"
-
- @interface KCMainViewController ()<uitableviewdatasource,uitableviewdelegate,uialertviewdelegate>{
- UITableView *_tableView;
- NSMutableArray *_contacts;
- NSIndexPath *_selectedIndexPath;
- }
-
- @end
-
- @implementation KCMainViewController
-
- - (void)viewDidLoad {
- [super viewDidLoad];
-
-
- [self initData];
-
-
- _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
-
-
- _tableView.dataSource=self;
-
- _tableView.delegate=self;
-
- [self.view addSubview:_tableView];
- }
-
- #pragma mark 加载数据
- -(void)initData{
- _contacts=[[NSMutableArray alloc]init];
-
- KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
- KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
- KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
- [_contacts addObject:group1];
-
-
-
- KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"];
- KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"];
- KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"];
- KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]];
- [_contacts addObject:group2];
-
-
-
- KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"];
- KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"];
-
- KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]];
- [_contacts addObject:group3];
-
-
- KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"];
- KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"];
- KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"];
- KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"];
- KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"];
- KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]];
- [_contacts addObject:group4];
-
-
- KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"];
- KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"];
- KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"];
- KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]];
- [_contacts addObject:group5];
-
- }
-
- #pragma mark - 数据源方法
- #pragma mark 返回分组数
- -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
- NSLog(@"计算分组数");
- return _contacts.count;
- }
-
- #pragma mark 返回每组行数
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
- NSLog(@"计算每组(组%i)行数",section);
- KCContactGroup *group1=_contacts[section];
- return group1.contacts.count;
- }
-
- #pragma mark返回每行的单元格
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
-
- NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row);
- KCContactGroup *group=_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
- UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
- cell.textLabel.text=[contact getName];
- cell.detailTextLabel.text=contact.phoneNumber;
- return cell;
- }
-
- #pragma mark 返回每组头标题名称
- -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
- NSLog(@"生成组(组%i)名称",section);
- KCContactGroup *group=_contacts[section];
- return group.name;
- }
-
- #pragma mark 返回每组尾部说明
- -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
- NSLog(@"生成尾部(组%i)详情",section);
- KCContactGroup *group=_contacts[section];
- return group.detail;
- }
-
- #pragma mark 返回每组标题索引
- -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
- NSLog(@"生成组索引");
- NSMutableArray *indexs=[[NSMutableArray alloc]init];
- for(KCContactGroup *group in _contacts){
- [indexs addObject:group.name];
- }
- return indexs;
- }
-
- #pragma mark - 代理方法
- #pragma mark 设置分组标题内容高度
- -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
- if(section==0){
- return 50;
- }
- return 40;
- }
-
- #pragma mark 设置每行高度(每行高度能够不同)
- -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
- return 45;
- }
-
- #pragma mark 设置尾部说明内容高度
- -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
- return 40;
- }
-
- #pragma mark 点击行
- -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
- _selectedIndexPath=indexPath;
- KCContactGroup *group=_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
-
- UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"System Info" message:[contact getName] delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
- alert.alertViewStyle=UIAlertViewStylePlainTextInput;
- UITextField *textField= [alert textFieldAtIndex:0];
- textField.text=contact.phoneNumber;
- [alert show];
- }
-
- #pragma mark 窗口的代理方法,用户保存数据
- -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
-
- if (buttonIndex==1) {
- UITextField *textField= [alertView textFieldAtIndex:0];
-
- KCContactGroup *group=_contacts[_selectedIndexPath.section];
- KCContact *contact=group.contacts[_selectedIndexPath.row];
- contact.phoneNumber=textField.text;
-
- [_tableView reloadData];
- }
- }
-
- #pragma mark 重写状态样式方法
- -(UIStatusBarStyle)preferredStatusBarStyle{
- return UIStatusBarStyleLightContent;
- }
- @end
在上面的代码中咱们经过修改模型来改变UI显示,这种方式是经典的MVC应用,在后面的代码中会常常看到。固然UI的刷新使用了UITableView的reloadData方法,该方法会从新调用数据源方法,包括计算分组、计算每一个分组的行数,生成单元格等刷新整个UITableView。固然这种方式在实际开发中是不可取的,咱们不可能由于修改了一我的的信息就刷新整个UITableViewView,此时咱们须要采用局部刷新。局部刷新使用起来很简单,只须要调用UITableView的另一个方法:
- #pragma mark 窗口的代理方法,用户保存数据
- -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
-
- if (buttonIndex==1) {
- UITextField *textField= [alertView textFieldAtIndex:0];
-
- KCContactGroup *group=_contacts[_selectedIndexPath.section];
- KCContact *contact=group.contacts[_selectedIndexPath.row];
- contact.phoneNumber=textField.text;
-
- NSArray *indexPaths=@[_selectedIndexPath];
- [_tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];
- }
- }
性能优化
前面已经说过UITableView中的单元格cell是在显示到用户可视区域后建立的,那么若是用户往下滚动就会继续建立显示在屏幕上的单元格,若是用户向上滚动返回到查看过的内容时一样会从新建立以前已经建立过的单元格。如此一来即便UITableView的内容不是太多,若是用户反复的上下滚动,内存也会瞬间飙升,更况且不少时候UITableView的内容是不少的(例如微博展现列表,基本向下滚动是没有底限的)。
前面一节中咱们曾经提到过如何优化UIScrollView,当时就是利用有限的UIImageView动态切换其内容来尽量减小资源占用。一样的,在UITableView中也能够采用相似的方式,只是这时咱们不是在滚动到指定位置后更改滚动的位置而是要将当前没有显示的Cell从新显示在将要显示的Cell的位置而后更新其内容。缘由就是UITableView中的Cell结构布局多是不一样的,经过从新定位是不可取的,而是须要重用已经再也不界面显示的已建立过的Cell。
固然,听起来这么作比较复杂,其实实现起来很简单,由于UITableView已经为咱们实现了这种机制。在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一个可重用标识,就能够将这个cell放到缓存池。而后在使用时使用指定的标识去缓存池中取得对应的cell而后修改cell内容便可。
上面的代码中已经打印了cell的地址,若是你们运行测试上下滚动UITableView会发现滚动时建立的cell地址是初始化时已经建立的。
这里再次给你们强调两点:
1. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)方法调用很频繁,不管是初始化、上下滚动、刷新都会调用此方法,全部在这里执行的操做必定要注意性能;
2. 可重用标识能够有多个,若是在UITableView中有多类结构不一样的Cell,能够经过这个标识进行缓存和从新。
UITableViewCell
1.自带的UITableViewCell
UITableViewCell是构建一个UITableView的基础,在UITableViewCell内部有一个UIView控件做为其余内容的容器,它上面有一个UIImageView和两个UILabel,经过UITableViewCellStyle属性能够对其样式进行控制。其结构以下:
有时候咱们会发现不少UITableViewCell右侧能够显示不一样的图标,在iOS中称之为访问器,点击能够触发不一样的事件,例如设置功能:
要设置这些图标只须要设置UITableViewCell的accesoryType属性,这是一个枚举类型具体含义以下:
- typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) {
- UITableViewCellAccessoryNone,
- UITableViewCellAccessoryDisclosureIndicator,
- UITableViewCellAccessoryDetailDisclosureButton,
- UITableViewCellAccessoryCheckmark,
- UITableViewCellAccessoryDetailButton NS_ENUM_AVAILABLE_IOS(7_0)
- };
例如在最近通话中咱们一般设置为详情图标,点击能够查看联系人详情:
很明显iOS设置中第一个accessoryType不在枚举之列,右侧的访问器类型是UISwitch控件,那么如何显示自定义的访问器呢?其实只要设置UITableViewCell的accessoryView便可,它支持任何UIView控件。假设咱们在通信录每组第一行放一个UISwitch,同时切换时能够输出对应信息:
-
- #import "KCMainViewController.h"
- #import "KCContact.h"
- #import "KCContactGroup.h"
-
- @interface KCMainViewController ()<uitableviewdatasource,uitableviewdelegate,uialertviewdelegate>{
- UITableView *_tableView;
- NSMutableArray *_contacts;
- NSIndexPath *_selectedIndexPath;
- }
-
- @end
-
- @implementation KCMainViewController
-
- - (void)viewDidLoad {
- [super viewDidLoad];
-
-
- [self initData];
-
-
- _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
-
-
- _tableView.dataSource=self;
-
- _tableView.delegate=self;
-
- [self.view addSubview:_tableView];
- }
-
- #pragma mark 加载数据
- -(void)initData{
- _contacts=[[NSMutableArray alloc]init];
-
- KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
- KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
- KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
- [_contacts addObject:group1];
-
-
-
- KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"];
- KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"];
- KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"];
- KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]];
- [_contacts addObject:group2];
-
-
-
- KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"];
- KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"];
-
- KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]];
- [_contacts addObject:group3];
-
-
- KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"];
- KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"];
- KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"];
- KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"];
- KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"];
- KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]];
- [_contacts addObject:group4];
-
-
- KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"];
- KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"];
- KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"];
- KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]];
- [_contacts addObject:group5];
-
- }
-
- #pragma mark - 数据源方法
- #pragma mark 返回分组数
- -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
- NSLog(@"计算分组数");
- return _contacts.count;
- }
-
- #pragma mark 返回每组行数
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
- NSLog(@"计算每组(组%i)行数",section);
- KCContactGroup *group1=_contacts[section];
- return group1.contacts.count;
- }
-
- #pragma mark返回每行的单元格
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
-
- NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row);
- KCContactGroup *group=_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
-
-
- static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
- static NSString *cellIdentifierForFirstRow=@"UITableViewCellIdentifierKeyWithSwitch";
-
- UITableViewCell *cell;
- if (indexPath.row==0) {
- cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifierForFirstRow];
- }else{
- cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
- }
-
- if(!cell){
- if (indexPath.row==0) {
- cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierForFirstRow];
- UISwitch *sw=[[UISwitch alloc]init];
- [sw addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged];
- cell.accessoryView=sw;
-
- }else{
- cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
- cell.accessoryType=UITableViewCellAccessoryDetailButton;
- }
- }
-
- if(indexPath.row==0){
- ((UISwitch *)cell.accessoryView).tag=indexPath.section;
- }
-
- cell.textLabel.text=[contact getName];
- cell.detailTextLabel.text=contact.phoneNumber;
- NSLog(@"cell:%@",cell);
-
- return cell;
- }
-
- #pragma mark 返回每组头标题名称
- -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
- NSLog(@"生成组(组%i)名称",section);
- KCContactGroup *group=_contacts[section];
- return group.name;
- }
-
- #pragma mark 返回每组尾部说明
- -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
- NSLog(@"生成尾部(组%i)详情",section);
- KCContactGroup *group=_contacts[section];
- return group.detail;
- }
-
- #pragma mark 返回每组标题索引
- -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
- NSLog(@"生成组索引");
- NSMutableArray *indexs=[[NSMutableArray alloc]init];
- for(KCContactGroup *group in _contacts){
- [indexs addObject:group.name];
- }
- return indexs;
- }
-
- #pragma mark - 代理方法
- #pragma mark 设置分组标题内容高度
- -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
- if(section==0){
- return 50;
- }
- return 40;
- }
-
- #pragma mark 设置每行高度(每行高度能够不同)
- -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
- return 45;
- }
-
- #pragma mark 设置尾部说明内容高度
- -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
- return 40;
- }
-
- #pragma mark 点击行
- -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
- _selectedIndexPath=indexPath;
- KCContactGroup *group=_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
-
- UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"System Info" message:[contact getName] delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
- alert.alertViewStyle=UIAlertViewStylePlainTextInput;
- UITextField *textField= [alert textFieldAtIndex:0];
- textField.text=contact.phoneNumber;
- [alert show];
- }
-
- #pragma mark 窗口的代理方法,用户保存数据
- -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
-
- if (buttonIndex==1) {
- UITextField *textField= [alertView textFieldAtIndex:0];
-
- KCContactGroup *group=_contacts[_selectedIndexPath.section];
- KCContact *contact=group.contacts[_selectedIndexPath.row];
- contact.phoneNumber=textField.text;
-
- NSArray *indexPaths=@[_selectedIndexPath];
- [_tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];
- }
- }
-
-
- #pragma mark 重写状态样式方法
- -(UIStatusBarStyle)preferredStatusBarStyle{
- return UIStatusBarStyleLightContent;
- }
-
-
- #pragma mark 切换开关转化事件
- -(void)switchValueChange:(UISwitch *)sw{
- NSLog(@"section:%i,switch:%i",sw.tag, sw.on);
- }
- @end
最终运行效果:
注意:
1.因为此时咱们须要两种UITableViewCell样式,考虑到性能咱们须要在缓存池缓存两种Cell。
2.UISwitch继承于UIControl而不是UIView(固然UIControl最终也是继承于UIView),继承于UIControl的控件使用addTarget添加对应事件而不是代理,同时有“是否可用”、“是否高亮”、“是否选中”等属性;
3.上面代码中若是有些UITableViewCell的UISwitch设置为on当其余控件重用时状态也是on,解决这个问题能够在模型中设置对应的属性记录其状态,在生成cell时设置当前状态(为了尽量简化上面的代码这里就再也不修复这个问题);
2.自定义UITableViewCell
虽然系统自带的UITableViewCell已经够强大了,可是不少时候这并不能知足咱们的需求。例如新浪微博的Cell就没有那么简单:
没错,这个界面布局也是UITableView实现的,其中的内容就是UITableViewCell,只是这个UITableViewCell是用户自定义实现的。固然要实现上面的UITableViewCell三言两语咱们是说不完的,这里咱们实现一个简化版本,界面原型以下:
咱们对具体控件进行拆分:
在这个界面中有2个UIImageView控件和4个UILabel,整个界面显示效果相似于新浪微博的消息内容界面,可是又在新浪微博基础上进行了精简以致于利用现有知识可以顺利开发出来。
在前面的内容中咱们的数据都是手动构建的,在实际开发中天然不会这么作,这里咱们不妨将微博数据存储到plist文件中而后从plist文件读取数据构建模型对象(实际开发微博固然须要进行网络数据请求,这里只是进行模拟就再也不演示网络请求的内容)。假设plist文件内容以下:
接下来就定义一个KCStatusTableViewCell实现UITableViewCell,通常实现自定义UITableViewCell须要分为两步:第一初始化控件;第二设置数据,从新设置控件frame。缘由就是自定义Cell通常没法固定高度,不少时候高度须要随着内容改变。此外因为在单元格内部是没法控制单元格高度的,所以通常会定义一个高度属性用于在UITableView的代理事件中设置每一个单元格高度。
首先看一下微博模型KCStatus,这个模型主要的方法就是根据plist字典内容生成微博对象:
KCStatus.h
-
- #import
-
- @interface KCStatus : NSObject
-
- #pragma mark - 属性
- @property (nonatomic,assign) long long Id;
- @property (nonatomic,copy) NSString *profileImageUrl;
- @property (nonatomic,copy) NSString *userName;
- @property (nonatomic,assign) NSString *mbtype;
- @property (nonatomic,copy) NSString *createdAt;
- @property (nonatomic,copy) NSString *source;
- @property (nonatomic,copy) NSString *text;
-
-
-
- #pragma mark - 方法
- #pragma mark 根据字典初始化微博对象
- -(KCStatus *)initWithDictionary:(NSDictionary *)dic;
-
- #pragma mark 初始化微博对象(静态方法)
- +(KCStatus *)statusWithDictionary:(NSDictionary *)dic;
- @end
KCStatus.m
-
- #import "KCStatus.h"
-
- @implementation KCStatus
-
- #pragma mark 根据字典初始化微博对象
- -(KCStatus *)initWithDictionary:(NSDictionary *)dic{
- if(self=[super init]){
- self.Id=[dic[@"Id"] longLongValue];
- self.profileImageUrl=dic[@"profileImageUrl"];
- self.userName=dic[@"userName"];
- self.mbtype=dic[@"mbtype"];
- self.createdAt=dic[@"createdAt"];
- self.source=dic[@"source"];
- self.text=dic[@"text"];
- }
- return self;
- }
-
- #pragma mark 初始化微博对象(静态方法)
- +(KCStatus *)statusWithDictionary:(NSDictionary *)dic{
- KCStatus *status=[[KCStatus alloc]initWithDictionary:dic];
- return status;
- }
-
- -(NSString *)source{
- return [NSString stringWithFormat:@"来自 %@",_source];
- }
- @end
而后看一下自定义的Cell
KCStatusTableViewCell.h
-
- #import
- @class KCStatus;
-
- @interface KCStatusTableViewCell : UITableViewCell
-
- #pragma mark 微博对象
- @property (nonatomic,strong) KCStatus *status;
-
- #pragma mark 单元格高度
- @property (assign,nonatomic) CGFloat height;
-
- @end
KCStatusTableViewCell.m
-
- #import "KCStatusTableViewCell.h"
- #import "KCStatus.h"
- #define KCColor(r,g,b) [UIColor colorWithHue:r/255.0 saturation:g/255.0 brightness:b/255.0 alpha:1] //颜色宏定义
- #define kStatusTableViewCellControlSpacing 10 //控件间距
- #define kStatusTableViewCellBackgroundColor KCColor(251,251,251)
- #define kStatusGrayColor KCColor(50,50,50)
- #define kStatusLightGrayColor KCColor(120,120,120)
-
- #define kStatusTableViewCellAvatarWidth 40 //头像宽度
- #define kStatusTableViewCellAvatarHeight kStatusTableViewCellAvatarWidth
- #define kStatusTableViewCellUserNameFontSize 14
- #define kStatusTableViewCellMbTypeWidth 13 //会员图标宽度
- #define kStatusTableViewCellMbTypeHeight kStatusTableViewCellMbTypeWidth
- #define kStatusTableViewCellCreateAtFontSize 12
- #define kStatusTableViewCellSourceFontSize 12
- #define kStatusTableViewCellTextFontSize 14
-
-
- @interface KCStatusTableViewCell(){
- UIImageView *_avatar;
- UIImageView *_mbType;
- UILabel *_userName;
- UILabel *_createAt;
- UILabel *_source;
- UILabel *_text;
- }
-
- @end
-
- @implementation KCStatusTableViewCell
-
- - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
- if (self) {
- [self initSubView];
- }
- return self;
- }
-
- #pragma mark 初始化视图
- -(void)initSubView{
-
- _avatar=[[UIImageView alloc]init];
- [self addSubview:_avatar];
-
- _userName=[[UILabel alloc]init];
- _userName.textColor=kStatusGrayColor;
- _userName.font=[UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize];
- [self addSubview:_userName];
-
- _mbType=[[UIImageView alloc]init];
- [self addSubview:_mbType];
-
- _createAt=[[UILabel alloc]init];
- _createAt.textColor=kStatusLightGrayColor;
- _createAt.font=[UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize];
- [self addSubview:_createAt];
-
- _source=[[UILabel alloc]init];
- _source.textColor=kStatusLightGrayColor;
- _source.font=[UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize];
- [self addSubview:_source];
-
- _text=[[UILabel alloc]init];
- _text.textColor=kStatusGrayColor;
- _text.font=[UIFont systemFontOfSize:kStatusTableViewCellTextFontSize];
- _text.numberOfLines=0;
- [self addSubview:_text];
- }
-
- #pragma mark 设置微博
- -(void)setStatus:(KCStatus *)status{
-
- CGFloat avatarX=10,avatarY=10;
- CGRect avatarRect=CGRectMake(avatarX, avatarY, kStatusTableViewCellAvatarWidth, kStatusTableViewCellAvatarHeight);
- _avatar.image=[UIImage imageNamed:status.profileImageUrl];
- _avatar.frame=avatarRect;
-
-
-
- CGFloat userNameX= CGRectGetMaxX(_avatar.frame)+kStatusTableViewCellControlSpacing ;
- CGFloat userNameY=avatarY;
-
- CGSize userNameSize=[status.userName sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize]}];
- CGRect userNameRect=CGRectMake(userNameX, userNameY, userNameSize.width,userNameSize.height);
- _userName.text=status.userName;
- _userName.frame=userNameRect;
-
-
-
- CGFloat mbTypeX=CGRectGetMaxX(_userName.frame)+kStatusTableViewCellControlSpacing;
- CGFloat mbTypeY=avatarY;
- CGRect mbTypeRect=CGRectMake(mbTypeX, mbTypeY, kStatusTableViewCellMbTypeWidth, kStatusTableViewCellMbTypeHeight);
- _mbType.image=[UIImage imageNamed:status.mbtype];
- _mbType.frame=mbTypeRect;
-
-
-
- CGSize createAtSize=[status.createdAt sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize]}];
- CGFloat createAtX=userNameX;
- CGFloat createAtY=CGRectGetMaxY(_avatar.frame)-createAtSize.height;
- CGRect createAtRect=CGRectMake(createAtX, createAtY, createAtSize.width, createAtSize.height);
- _createAt.text=status.createdAt;
- _createAt.frame=createAtRect;
-
-
-
- CGSize sourceSize=[status.source sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize]}];
- CGFloat sourceX=CGRectGetMaxX(_createAt.frame)+kStatusTableViewCellControlSpacing;
- CGFloat sourceY=createAtY;
- CGRect sourceRect=CGRectMake(sourceX, sourceY, sourceSize.width,sourceSize.height);
- _source.text=status.source;
- _source.frame=sourceRect;
-
-
-
- CGFloat textX=avatarX;
- CGFloat textY=CGRectGetMaxY(_avatar.frame)+kStatusTableViewCellControlSpacing;
- CGFloat textWidth=self.frame.size.width-kStatusTableViewCellControlSpacing*2;
- CGSize textSize=[status.text boundingRectWithSize:CGSizeMake(textWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellTextFontSize]} context:nil].size;
- CGRect textRect=CGRectMake(textX, textY, textSize.width, textSize.height);
- _text.text=status.text;
- _text.frame=textRect;
-
- _height=CGRectGetMaxY(_text.frame)+kStatusTableViewCellControlSpacing;
- }
-
- #pragma mark 重写选择事件,取消选中
- -(void)setSelected:(BOOL)selected animated:(BOOL)animated{
-
- }
- @end
这是咱们自定义Cell这个例子的核心,自定义Cell分为两个步骤:首先要进行各类控件的初始化工做,这个过程当中只要将控件放到Cell的View中同时设置控件显示内容的格式(字体大小、颜色等)便可;而后在数据对象设置方法中进行各个控件的布局(大小、位置)。在代码中有几点须要重点提示你们:
1).对于单行文本数据的显示调用+ (UIFont *)systemFontOfSize:(CGFloat)fontSize;方法来获得文本宽度和高度。
2).对于多行文本数据的显示调用- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context ;方法来获得文本宽度和高度;同时注意在此以前须要设置文本控件的numberOfLines属性为0。
3).一般咱们会在自定义Cell中设置一个高度属性,用于外界方法调用,由于Cell内部设置Cell的高度是没有用的,UITableViewCell在初始化时会从新设置高度。
最后咱们看一下自定义Cell的使用过程:
KCStatusViewController.m
-
- #import "KCStatusCellViewController.h"
- #import "KCStatus.h"
- #import "KCStatusTableViewCell.h"
-
- @interface KCStatusCellViewController ()<uitableviewdatasource,uitableviewdelegate,uialertviewdelegate>{
- UITableView *_tableView;
- NSMutableArray *_status;
- NSMutableArray *_statusCells;
- }
- @end
-
- @implementation KCStatusCellViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
-
-
- [self initData];
-
-
- _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
-
-
- _tableView.dataSource=self;
-
- _tableView.delegate=self;
-
- [self.view addSubview:_tableView];
- }
-
- #pragma mark 加载数据
- -(void)initData{
- NSString *path=[[NSBundle mainBundle] pathForResource:@"StatusInfo" ofType:@"plist"];
- NSArray *array=[NSArray arrayWithContentsOfFile:path];
- _status=[[NSMutableArray alloc]init];
- _statusCells=[[NSMutableArray alloc]init];
- [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- [_status addObject:[KCStatus statusWithDictionary:obj]];
- KCStatusTableViewCell *cell=[[KCStatusTableViewCell alloc]init];
- [_statusCells addObject:cell];
- }];
- }
- #pragma mark - 数据源方法
- #pragma mark 返回分组数
- -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
- return 1;
- }
-
- #pragma mark 返回每组行数
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
-
- return _status.count;
- }
-
- #pragma mark返回每行的单元格
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
- static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
- KCStatusTableViewCell *cell;
- cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
- if(!cell){
- cell=[[KCStatusTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
- }
-
- KCStatus *status=_status[indexPath.row];
- cell.status=status;
- return cell;
- }
-
- #pragma mark - 代理方法
- #pragma mark 从新设置单元格高度
- -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
-
- KCStatusTableViewCell *cell= _statusCells[indexPath.row];
- cell.status=_status[indexPath.row];
- return cell.height;
- }
-
- #pragma mark 重写状态样式方法
- -(UIStatusBarStyle)preferredStatusBarStyle{
- return UIStatusBarStyleLightContent;
- }
- @end
这个类中须要重点强调一下:Cell的高度须要从新设置(前面说过不管Cell内部设置多高都没有用,须要从新设置),这里采用的方法是首先建立对应的Cell,而后在- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;方法中设置微博数据计算高度通知UITableView。
最后咱们看一下运行的效果:
经常使用操做
UITableView和UITableViewCell提供了强大的操做功能,这一节中会重点讨论删除、增长、排序等操做。为了方便演示咱们仍是在以前的通信录的基础上演示,在此以前先来给视图控制器添加一个工具条,在工具条左侧放一个删除按钮,右侧放一个添加按钮:
- #pragma mark 添加工具栏
- -(void)addToolbar{
- CGRect frame=self.view.frame;
- _toolbar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, kContactToolbarHeight)];
-
- [self.view addSubview:_toolbar];
- UIBarButtonItem *removeButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(remove)];
- UIBarButtonItem *flexibleButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
- UIBarButtonItem *addButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)];
- NSArray *buttonArray=[NSArray arrayWithObjects:removeButton,flexibleButton,addButton, nil];
- _toolbar.items=buttonArray;
- }
1.删除
在UITableView中不管是删除操做仍是添加操做都是经过修改UITableView的编辑状态来改变的(除非你不用UITableView自带的删除功能)。在删除按钮中咱们设置UITableView的编辑状态:
- #pragma mark 删除
- -(void)remove{
-
-
-
- [_tableView setEditing:!_tableView.isEditing animated:true];
- }
点击删除按钮会在Cell的左侧显示删除按钮:
此时点击左侧删除图标右侧出现删除:
用过iOS的朋友都知道,通常这种Cell若是向左滑动右侧就会出现删除按钮直接删除就能够了。其实实现这个功能只要实现代理-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;方法,只要实现了此方法向左滑动就会显示删除按钮。只要点击删除按钮这个方法就会调用,可是须要注意的是不管是删除仍是添加都是执行这个方法,只是第二个参数类型不一样。下面看一下具体的删除实现:
- #pragma mark 删除操做
- -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
- KCContactGroup *group =_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
- if (editingStyle==UITableViewCellEditingStyleDelete) {
- [group.contacts removeObject:contact];
-
-
-
- [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
-
-
- if (group.contacts.count==0) {
- [_contacts removeObject:group];
- [tableView reloadData];
- }
- }
- }
从这段代码咱们再次看到了MVC的思想,要修改UI先修改数据。并且咱们看到了另外一个刷新表格的方法- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;,使用这个方法能够再删除以后刷新对应的单元格。效果以下:
2.添加
添加和删除操做都是设置UITableView的编辑状态,具体是添加仍是删除须要根据代理方法-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;的返回值来肯定。所以这里咱们定义一个变量来记录点击了哪一个按钮,根据点击按钮的不一样在这个方法中返回不一样的值。
- #pragma mark 取得当前操做状态,根据不一样的状态左侧出现不一样的操做按钮
- -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
- if (_isInsert) {
- return UITableViewCellEditingStyleInsert;
- }
- return UITableViewCellEditingStyleDelete;
- }
- #pragma mark 编辑操做(删除或添加)
- -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
- KCContactGroup *group =_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
- if (editingStyle==UITableViewCellEditingStyleDelete) {
- [group.contacts removeObject:contact];
-
-
-
- [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
-
-
- if (group.contacts.count==0) {
- [_contacts removeObject:group];
- [tableView reloadData];
- }
- }else if(editingStyle==UITableViewCellEditingStyleInsert){
- KCContact *newContact=[[KCContact alloc]init];
- newContact.firstName=@"first";
- newContact.lastName=@"last";
- newContact.phoneNumber=@"12345678901";
- [group.contacts insertObject:newContact atIndex:indexPath.row];
- [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
- }
- }
运行效果:
3.排序
只要实现-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;代理方法当UITableView处于编辑状态时就能够排序。
- #pragma mark 排序
- -(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
- KCContactGroup *sourceGroup =_contacts[sourceIndexPath.section];
- KCContact *sourceContact=sourceGroup.contacts[sourceIndexPath.row];
- KCContactGroup *destinationGroup =_contacts[destinationIndexPath.section];
-
- [sourceGroup.contacts removeObject:sourceContact];
- if(sourceGroup.contacts.count==0){
- [_contacts removeObject:sourceGroup];
- [tableView reloadData];
- }
-
- [destinationGroup.contacts insertObject:sourceContact atIndex:destinationIndexPath.row];
-
- }
运行效果:
最后给你们附上上面几种操做的完整代码:
- #import "KCContactViewController.h"
- #import "KCContact.h"
- #import "KCContactGroup.h"
- #define kContactToolbarHeight 44
- @interface KCContactViewController ()<uitableviewdatasource,uitableviewdelegate,uialertviewdelegate>{
- UITableView *_tableView;
- UIToolbar *_toolbar;
- NSMutableArray *_contacts;
- NSIndexPath *_selectedIndexPath;
- BOOL _isInsert;
- }
- @end
- @implementation KCContactViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
-
-
- [self initData];
-
-
- _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
- _tableView.contentInset=UIEdgeInsetsMake(kContactToolbarHeight, 0, 0, 0);
- [self.view addSubview:_tableView];
-
-
- [self addToolbar];
-
-
- _tableView.dataSource=self;
-
- _tableView.delegate=self;
-
-
- }
- #pragma mark 加载数据
- -(void)initData{
- _contacts=[[NSMutableArray alloc]init];
-
- KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
- KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
- KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
- [_contacts addObject:group1];
-
-
-
- KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"];
- KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"];
- KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"];
- KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]];
- [_contacts addObject:group2];
-
-
-
- KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"];
- KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"];
-
- KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]];
- [_contacts addObject:group3];
-
-
- KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"];
- KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"];
- KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"];
- KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"];
- KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"];
- KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]];
- [_contacts addObject:group4];
-
-
- KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"];
- KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"];
- KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"];
- KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]];
- [_contacts addObject:group5];
-
- }
- #pragma mark 添加工具栏
- -(void)addToolbar{
- CGRect frame=self.view.frame;
- _toolbar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, kContactToolbarHeight)];
-
- [self.view addSubview:_toolbar];
- UIBarButtonItem *removeButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(remove)];
- UIBarButtonItem *flexibleButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
- UIBarButtonItem *addButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)];
- NSArray *buttonArray=[NSArray arrayWithObjects:removeButton,flexibleButton,addButton, nil];
- _toolbar.items=buttonArray;
- }
- #pragma mark 删除
- -(void)remove{
-
-
- _isInsert=false;
- [_tableView setEditing:!_tableView.isEditing animated:true];
- }
- #pragma mark 添加
- -(void)add{
- _isInsert=true;
- [_tableView setEditing:!_tableView.isEditing animated:true];
- }
- #pragma mark - 数据源方法
- #pragma mark 返回分组数
- -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
- return _contacts.count;
- }
- #pragma mark 返回每组行数
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
- KCContactGroup *group1=_contacts[section];
- return group1.contacts.count;
- }
- #pragma mark返回每行的单元格
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
-
- KCContactGroup *group=_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
- static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
-
- UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
-
- if(!cell){
- cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
- }
-
- cell.textLabel.text=[contact getName];
- cell.detailTextLabel.text=contact.phoneNumber;
-
- return cell;
- }
- #pragma mark - 代理方法
- #pragma mark 设置分组标题
- -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
- KCContactGroup *group=_contacts[section];
- return group.name;
- }
- #pragma mark 编辑操做(删除或添加)
- -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
- KCContactGroup *group =_contacts[indexPath.section];
- KCContact *contact=group.contacts[indexPath.row];
- if (editingStyle==UITableViewCellEditingStyleDelete) {
- [group.contacts removeObject:contact];
-
-
-
- [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
-
-
- if (group.contacts.count==0) {
- [_contacts removeObject:group];
- [tableView reloadData];
- }
- }else if(editingStyle==UITableViewCellEditingStyleInsert){
- KCContact *newContact=[[KCContact alloc]init];
- newContact.firstName=@"first";
- newContact.lastName=@"last";
- newContact.phoneNumber=@"12345678901";
- [group.contacts insertObject:newContact atIndex:indexPath.row];
- [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
- }
- }
- #pragma mark 排序
- -(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
- KCContactGroup *sourceGroup =_contacts[sourceIndexPath.section];
- KCContact *sourceContact=sourceGroup.contacts[sourceIndexPath.row];
- KCContactGroup *destinationGroup =_contacts[destinationIndexPath.section];
-
- [sourceGroup.contacts removeObject:sourceContact];
- [destinationGroup.contacts insertObject:sourceContact atIndex:destinationIndexPath.row];
- if(sourceGroup.contacts.count==0){
- [_contacts removeObject:sourceGroup];
- [tableView reloadData];
- }
- }
- #pragma mark 取得当前操做状态,根据不一样的状态左侧出现不一样的操做按钮
- -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
- if (_isInsert) {
- return UITableViewCellEditingStyleInsert;
- }
- return UITableViewCellEditingStyleDelete;
- }
- #pragma mark 重写状态样式方法
- -(UIStatusBarStyle)preferredStatusBarStyle{
- return UIStatusBarStyleLightContent;
- }
- @end
经过前面的演示这里简单总结一些UITableView的刷新方法:
- (void)reloadData;刷新整个表格。
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);刷新指定的分组和行。
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);刷新指定的分组。
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;删除时刷新指定的行数据。
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;添加时刷新指定的行数据。
UITableViewController
不少时候一个UIViewController中只有一个UITableView,所以苹果官方为了方便你们开发直接提供了一个UITableViewController,这个控制器 UITableViewController实现了UITableView数据源和代理协议,内部定义了一个tableView属性供外部访问,同时自动铺满整个屏幕、自动伸缩以方便咱们的开发。固然UITableViewController也并非简单的帮咱们定义完UITableView而且设置了数据源、代理而已,它还有其余强大的功能,例如刷新控件、滚动过程当中固定分组标题等。
有时候一个表格中的数据特别多,检索起来就显得麻烦,这个时候能够实现一个搜索功能帮助用户查找数据,其实搜索的原理很简单:修改模型、刷新表格。下面使用UITableViewController简单演示一下这个功能:
- #import "KCContactTableViewController.h"
- #import "KCContact.h"
- #import "KCContactGroup.h"
- #define kSearchbarHeight 44
- @interface KCContactTableViewController (){
- UITableView *_tableView;
- UISearchBar *_searchBar;
-
- NSMutableArray *_contacts;
- NSMutableArray *_searchContacts;
- BOOL _isSearching;
- }
- @end
- @implementation KCContactTableViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- [self initData];
-
-
- [self addSearchBar];
- }
- #pragma mark - 数据源方法
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
- if (_isSearching) {
- return 1;
- }
- return _contacts.count;;
- }
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- if (_isSearching) {
- return _searchContacts.count;
- }
- KCContactGroup *group1=_contacts[section];
- return group1.contacts.count;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- KCContact *contact=nil;
-
- if (_isSearching) {
- contact=_searchContacts[indexPath.row];
- }else{
- KCContactGroup *group=_contacts[indexPath.section];
- contact=group.contacts[indexPath.row];
- }
-
- static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
-
-
- UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
-
- if(!cell){
- cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
- }
-
- cell.textLabel.text=[contact getName];
- cell.detailTextLabel.text=contact.phoneNumber;
-
- return cell;
- }
- #pragma mark - 代理方法
- #pragma mark 设置分组标题
- -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
- KCContactGroup *group=_contacts[section];
- return group.name;
- }
- #pragma mark - 搜索框代理
- #pragma mark 取消搜索
- -(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
- _isSearching=NO;
- _searchBar.text=@"";
- [self.tableView reloadData];
- }
- #pragma mark 输入搜索关键字
- -(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
- if([_searchBar.text isEqual:@""]){
- _isSearching=NO;
- [self.tableView reloadData];
- return;
- }
- [self searchDataWithKeyWord:_searchBar.text];
- }
- #pragma mark 点击虚拟键盘上的搜索时
- -(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
-
- [self searchDataWithKeyWord:_searchBar.text];
-
- [_searchBar resignFirstResponder];
- }
- #pragma mark 重写状态样式方法
- -(UIStatusBarStyle)preferredStatusBarStyle{
- return UIStatusBarStyleLightContent;
- }
- #pragma mark 加载数据
- -(void)initData{
- _contacts=[[NSMutableArray alloc]init];
-
- KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
- KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
- KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
- [_contacts addObject:group1];
-
-
-
- KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"];
- KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"];
- KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"];
- KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]];
- [_contacts addObject:group2];
-
-
-
- KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"];
- KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"];
-
- KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]];
- [_contacts addObject:group3];
-
-
- KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"];
- KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"];
- KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"];
- KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"];
- KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"];
- KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]];
- [_contacts addObject:group4];
-
-
- KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"];
- KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"];
- KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"];
- KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]];
- [_contacts addObject:group5];
-
- }
- #pragma mark 搜索造成新数据
- -(void)searchDataWithKeyWord:(NSString *)keyWord{
- _isSearching=YES;
- _searchContacts=[NSMutableArray array];
- [_contacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- KCContactGroup *group=obj;
- [group.contacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- KCContact *contact=obj;
- if ([contact.firstName.uppercaseString containsString:keyWord.uppercaseString]||[contact.lastName.uppercaseString containsString:keyWord.uppercaseString]||[contact.phoneNumber containsString:keyWord]) {
- [_searchContacts addObject:contact];
- }
- }];
- }];
-
-
- [self.tableView reloadData];
- }
- #pragma mark 添加搜索栏
- -(void)addSearchBar{
- CGRect searchBarRect=CGRectMake(0, 0, self.view.frame.size.width, kSearchbarHeight);
- _searchBar=[[UISearchBar alloc]initWithFrame:searchBarRect];
- _searchBar.placeholder=@"Please input key word...";
-
-
-
- _searchBar.showsCancelButton=YES;
-
- _searchBar.delegate=self;
- self.tableView.tableHeaderView=_searchBar;
- }
- @end
运行效果:
在上面的搜索中除了使用一个_contacts变量去保存联系人数据还专门定义了一个_searchContact变量用于保存搜索的结果。在输入搜索关键字时咱们刷新了表格,此时会调用表格的数据源方法,在这个方法中咱们根据定义的搜索状态去决定显示原始数据仍是搜索结果。
咱们发现每次搜索完后都须要手动刷新表格来显示搜索结果,并且当没有搜索关键字的时候还须要将当前的tableView从新设置为初始状态。也就是这个过程当中咱们要用一个tableView显示两种状态的不一样数据,天然会提升程序逻辑复杂度。为了简化这个过程,咱们可使用UISearchDisplayController,UISearchDisplayController内部也有一个UITableView类型的对象searchResultsTableView,若是咱们设置它的数据源代理为当前控制器,那么它彻底能够像UITableView同样加载数据。同时它自己也有搜索监听的方法,咱们没必要在监听UISearchBar输入内容,直接使用它的方法便可自动刷新其内部表格。为了和前面的方法对比在下面的代码中没有直接删除原来的方式而是注释了对应代码你们能够对照学习:
- #import "KCContactTableViewControllerWithUISearchDisplayController.h"
- #import "KCContact.h"
- #import "KCContactGroup.h"
- #define kSearchbarHeight 44
- @interface KCContactTableViewControllerWithUISearchDisplayController ()<uisearchbardelegate,uisearchdisplaydelegate>{
- UITableView *_tableView;
- UISearchBar *_searchBar;
- UISearchDisplayController *_searchDisplayController;
- NSMutableArray *_contacts;
- NSMutableArray *_searchContacts;
-
- }
- @end
- @implementation KCContactTableViewControllerWithUISearchDisplayController
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- [self initData];
-
-
- [self addSearchBar];
- }
- #pragma mark - 数据源方法
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
-
- if (tableView==self.searchDisplayController.searchResultsTableView) {
- return 1;
- }
- return _contacts.count;;
- }
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
-
- if (tableView==self.searchDisplayController.searchResultsTableView) {
- return _searchContacts.count;
- }
- KCContactGroup *group1=_contacts[section];
- return group1.contacts.count;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- KCContact *contact=nil;
-
-
- if (tableView==self.searchDisplayController.searchResultsTableView) {
- contact=_searchContacts[indexPath.row];
- }else{
- KCContactGroup *group=_contacts[indexPath.section];
- contact=group.contacts[indexPath.row];
- }
-
- static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
-
-
- UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
-
- if(!cell){
- cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
- }
-
- cell.textLabel.text=[contact getName];
- cell.detailTextLabel.text=contact.phoneNumber;
-
- return cell;
- }
- #pragma mark - 代理方法
- #pragma mark 设置分组标题
- -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
- if (tableView==self.searchDisplayController.searchResultsTableView) {
- return @"搜索结果";
- }
- KCContactGroup *group=_contacts[section];
- return group.name;
- }
- #pragma mark 选中以前
- -(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
- [_searchBar resignFirstResponder];
- return indexPath;
- }
- #pragma mark - 搜索框代理
- #pragma mark - UISearchDisplayController代理方法
- -(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
- [self searchDataWithKeyWord:searchString];
- return YES;
- }
- #pragma mark 重写状态样式方法
- -(UIStatusBarStyle)preferredStatusBarStyle{
- return UIStatusBarStyleLightContent;
- }
- #pragma mark 加载数据
- -(void)initData{
- _contacts=[[NSMutableArray alloc]init];
-
- KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
- KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
- KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
- [_contacts addObject:group1];
-
-
-
- KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"];
- KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"];
- KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"];
- KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]];
- [_contacts addObject:group2];
-
-
-
- KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"];
- KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"];
-
- KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]];
- [_contacts addObject:group3];
-
-
- KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"];
- KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"];
- KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"];
- KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"];
- KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"];
- KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]];
- [_contacts addObject:group4];
-
-
- KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"];
- KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"];
- KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"];
- KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]];
- [_contacts addObject:group5];
-
- }
- #pragma mark 搜索造成新数据
- -(void)searchDataWithKeyWord:(NSString *)keyWord{
-
- _searchContacts=[NSMutableArray array];
- [_contacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- KCContactGroup *group=obj;
- [group.contacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- KCContact *contact=obj;
- if ([contact.firstName.uppercaseString containsString:keyWord.uppercaseString]||[contact.lastName.uppercaseString containsString:keyWord.uppercaseString]||[contact.phoneNumber containsString:keyWord]) {
- [_searchContacts addObject:contact];
- }
- }];
- }];
-
-
-
- }
- #pragma mark 添加搜索栏
- -(void)addSearchBar{
- _searchBar=[[UISearchBar alloc]init];
- [_searchBar sizeToFit];
- _searchBar.placeholder=@"Please input key word...";
- _searchBar.autocapitalizationType=UITextAutocapitalizationTypeNone;
- _searchBar.showsCancelButton=YES;
-
- _searchBar.delegate=self;
- self.tableView.tableHeaderView=_searchBar;
- _searchDisplayController=[[UISearchDisplayController alloc]initWithSearchBar:_searchBar contentsController:self];
- _searchDisplayController.delegate=self;
- _searchDisplayController.searchResultsDataSource=self;
- _searchDisplayController.searchResultsDelegate=self;
- [_searchDisplayController setActive:NO animated:YES];
- }
- @end
运行效果:
注意:若是使用Storyboard或xib方式建立上述代码则无需定义UISearchDisplayController成员变量,由于每一个UIViewController中已经有一个searchDisplayController对象。
MVC模式
经过UITableView的学习相信你们对于iOS的MVC已经有一个大体的了解,这里简单的分析一下iOS中MVC模式的设计方式。在iOS中多数数据源视图控件(View)都有一个dataSource属性用于和控制器(Controller)交互,而数据来源咱们通常会以数据模型(Model)的形式进行定义,View不直接和模型交互,而是经过Controller间接读取数据。
就拿前面的联系人应用举例,UITableView做为视图(View)并不能直接访问模型Contact,它要显示联系人信息只能经过控制器(Controller)来提供数据源方法。一样的控制器自己就拥有视图控件,能够操做视图,也就是说视图和控制器之间能够互相访问。而模型既不能访问视图也不能访问控制器。具体依赖关系以下图: