UITableViewhtml
基本介绍api
UITableView有两种风格:UITableViewStylePlain和UITableViewStyleGrouped。这二者操做起来其实并无本质区别,只是后者按分组样式显示前者按照普通样式显示而已。数组
在UITableView中数据只有行的概念,并无列的概念,由于在手机操做系统中显示多列是不利于操做的。UITableView中每行数据都是一个UITableViewCell,在这个控件中为了显示更多的信息,iOS已经在其内部设置好了多个子控件以供开发者使用。若是咱们查看UITableViewCell的声明文件能够发如今内部有一个UIView控件(contentView,做为其余元素的父控件)、两个UILable控件(textLabel、detailTextLabel)、一个UIImage控件(imageView),分别用于容器、显示内容、详情和图片。使用效果相似于微信、QQ信息列表。缓存
固然,这些子控件并不必定要所有使用,具体操做时能够经过UITableViewCellStyle进行设置,具体每一个枚举表示的意思已经在代码中进行了注释:性能优化
typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault, // 左侧显示textLabel(不显示detailTextLabel),imageView可选(显示在最左边) UITableViewCellStyleValue1, // 左侧显示textLabel、右侧显示detailTextLabel(默认蓝色),imageView可选(显示在最左边) UITableViewCellStyleValue2, // 左侧依次显示textLabel(默认蓝色)和detailTextLabel,imageView可选(显示在最左边) UITableViewCellStyleSubtitle // 左上方显示textLabel,左下方显示detailTextLabel(默认灰色),imageView可选(显示在最左边) };
数据源微信
因为iOS是遵循MVC模式设计的,不少操做都是经过代理和外界沟通的,但对于数据源控件除了代理还有一个数据源属性,经过它和外界进行数据交互。 对于UITableView设置完dataSource后须要实现UITableViewDataSource协议,在这个协议中定义了多种 数据操做方法,下面经过建立一个简单的联系人管理进行演示:app
首先咱们须要建立一个联系人模型KCContact(通信录)ide
KCContact.h函数
#import <Foundation/Foundation.h> //联系人模型 @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 *)laseName andPhoneNumber:(NSString *)phoneNumber; #pragma mark 取得姓名 -(NSString *)getName; #pragma mark 带参数的静态对象初始化方法 +(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)laseName andPhoneNumber:(NSString *)phoneNumber; @end
KCContact.m工具
#import "KCContact.h" @implementation KCContact //获得数据源的姓和名的方法 -(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)laseName andPhoneNumber:(NSString *)phoneNumber{ if (self = [super init]) { self.firstName = firstName; self.lastName = laseName; self.phoneNumber = phoneNumber; } return self; } //拼接 姓+名 的方法 -(NSString *)getName{ return [NSString stringWithFormat:@"%@%@", _firstName,_lastName]; } +(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)laseName andPhoneNumber:(NSString *)phoneNumber{ KCContact *contact1 = [[KCContact alloc]initWithFirstName:firstName andLastName:laseName andPhoneNumber:phoneNumber]; return contact1; } @end
联系人分组模型(好比姓刘的,姓张的都各自是一组)KCContactGroup
KCContactGroup.h
#import <Foundation/Foundation.h> #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方法中建立一些模拟数据同时实现数据源协议方法:
ViewController.h
#import <UIKit/UIKit.h> @interface ViewController : UIViewController<UIAlertViewDelegate,UITableViewDelegate,UITableViewDataSource> @end
ViewController.m
#import "ViewController.h" #import "KCContact.h" #import "KCContactGroup.h" @interface ViewController (){ UITableView *myTableView;//新建一个UITableView NSMutableArray *contacts;//联系人模型 NSIndexPath *selectedIndexPath;//当前选中的组和行 UIToolbar *myToolbar; BOOL isInsert;//记录是点击了插入仍是删除按钮 } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据(!!!很重要) [self initData]; //建立一个分组样式的UITableView myTableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; //设置数据源,注意必须实现对应的UITableViewDataSource协议 myTableView.dataSource = self; myTableView.delegate = self; [self.view addSubview:myTableView]; /** UITableView和UITableViewCell提供了强大的操做功能,这一节中会重点讨论删除、增长、排序等操做。为了方便演示咱们仍是在以前的通信录的基础上演示,在此以前先来给视图控制器添加一个工具条,在工具条左侧放一个删除按钮,右侧放一个添加按钮: */ myToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen]bounds].size.width, 64)]; myToolbar.backgroundColor = [UIColor redColor]; // [self.view addSubview:myToolbar]; //添加删除按钮 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]; // myToolbar.items = ButtonArray; } #pragma mark 加载数据 -(void)initData{ contacts = [[NSMutableArray alloc]init]; KCContact *contact1 = [KCContact initWithFirstName:@"liu" andLastName:@"bo" andPhoneNumber:@"18812345678"]; KCContact *contact2 = [KCContact initWithFirstName:@"wang" andLastName:@"zhaohua" andPhoneNumber:@"18812345678"]; KCContactGroup *group1 = [KCContactGroup initWithName:@"jiaren" andDetail:@"womenshiyijiaren" andContacts:[NSMutableArray arrayWithObjects:contact1, contact2, nil]]; [contacts addObject:group1]; KCContact *contact3 = [KCContact initWithFirstName:@"zhang" andLastName:@"bing" andPhoneNumber:@"12345678900"]; KCContact *contact4 = [KCContact initWithFirstName:@"wu" andLastName:@"wei" andPhoneNumber:@"98765432100"]; KCContact *contact5 = [KCContact initWithFirstName:@"zhang" andLastName:@"san" andPhoneNumber:@"12345612345"]; KCContactGroup *group2 = [KCContactGroup initWithName:@"pengyou" andDetail:@"womenshipengyou" andContacts:[NSMutableArray arrayWithObjects:contact3, contact4, contact5, nil]]; [contacts addObject:group2]; KCContact *contact6 = [KCContact initWithFirstName:@"li" andLastName:@"si" andPhoneNumber:@"12345555555"]; KCContact *contact7 = [KCContact initWithFirstName:@"wang" andLastName:@"wu" andPhoneNumber:@"88888888888"]; KCContactGroup *group3 = [KCContactGroup initWithName:@"tongxue" andDetail:@"womenshitongxue" andContacts:[NSMutableArray arrayWithObjects:contact6, contact7, nil]]; [contacts addObject:group3]; KCContact *contact8 = [KCContact initWithFirstName:@"hi" andLastName:@"pi" andPhoneNumber:@"12345555555"]; KCContact *contact9 = [KCContact initWithFirstName:@"kang" andLastName:@"gu" andPhoneNumber:@"88888888888"]; KCContact *contact10 = [KCContact initWithFirstName:@"roi" andLastName:@"sfi" andPhoneNumber:@"12345555555"]; KCContact *contact11 = [KCContact initWithFirstName:@"fang" andLastName:@"ii" andPhoneNumber:@"88888888888"]; KCContact *contact12 = [KCContact initWithFirstName:@"tyng" andLastName:@"rd" andPhoneNumber:@"88888888888"]; KCContactGroup *group4 = [KCContactGroup initWithName:@"qinqi" andDetail:@"womenshiqinqi" andContacts:[NSMutableArray arrayWithObjects:contact8, contact9, contact10, contact11, contact12, nil]]; [contacts addObject:group4]; KCContact *contact13 = [KCContact initWithFirstName:@"roi" andLastName:@"sfi" andPhoneNumber:@"12345555555"]; KCContact *contact14 = [KCContact initWithFirstName:@"fang" andLastName:@"ii" andPhoneNumber:@"88888888888"]; KCContact *contact15 = [KCContact initWithFirstName:@"tyng" andLastName:@"rd" andPhoneNumber:@"88888888888"]; KCContactGroup *group5 = [KCContactGroup initWithName:@"tongshi" andDetail:@"womenshitongshi" 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(@"计算每组(组%li)行数",(long)section); KCContactGroup * group1 = contacts[section]; return group1.contacts.count; } #pragma mark 返回每行的单元格 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //NSIndexPath是一个结构体,记录了组和行的信息 NSLog(@"生成单元格(组:%li 行:%li)",(long)indexPath.section,(long)indexPath.row); KCContactGroup *group = contacts[indexPath.section]; KCContact *contact = group.contacts[indexPath.row]; // //每行cell上面的内容(----------------普通方法建立cell---------------------) // UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil]; // /** // (----------------优化方法建立cell---------------------) // * 优化UITableView,这时咱们不是在滚动到指定位置后更改滚动的位置而是要将当前没有显示的Cell从新显示在将要显示的Cell的位置而后更新其内容。缘由就是UITableView中的Cell结构布局多是不一样的,经过从新定位是不可取的,而是须要重用已经再也不界面显示的已建立过的Cell。 // // UITableView已经为咱们实现了这种机制。在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一个可重用标识,就能够将这个cell放到缓存池。而后在使用时使用指定的标识去缓存池中取得对应的cell而后修改cell内容便可。 // */ // //因为此方法调用十分频繁,cell的 标示 声明成 静态变量 有助于性能优化 // static NSString *cellIdentifier = @"UITanleViewCellIdentifierKey1"; // //首先根据标识去缓存池取 // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; // //若是缓存池没有则从新建立,并放到缓存池中 // if (!cell) { // cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; // } /** * UITableViewCell右侧能够显示不一样的图标,在iOS中称之为访问器,点击能够触发不一样的事件,例如通信录右边的 联系人详情按钮 ,或者 声音,Wifi等设置 右边的开关!!!!!!!!!!!!!!! 在这里示例将通信录第一行右边设置为 开关 , 其他的右边设置为 联系人详情按钮 */ //因为此方法调用十分频繁,cell的 标示 声明成 静态变量 有助于性能优化 //注意: 因为此时咱们须要两种UITableViewCell样式,考虑到性能咱们须要在缓存池缓存两种Cell。 static NSString *cellIdentifier = @"UITableViewCellIdentifierKey1"; static NSString *cellIdentifierForFiestRow = @"UITableViewCellIdentifierKeyWithSwitch"; //首先根据标识去缓存池取 UITableViewCell *cell; if (indexPath.row == 0) { cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierForFiestRow]; }else{ cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; } //若是缓存池没有则从新建立,并放到缓存池中 if (!cell) { if (indexPath.row == 0) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierForFiestRow]; //在第一行右边建立开关 UISwitch *sw = [[UISwitch alloc]init]; [sw addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged]; //UISwitch继承于UIControl而不是UIView(固然UIControl最终也是继承于UIView),继承于UIControl的控件使用addTarget添加对应事件而不是代理,同时有“是否可用”、“是否高亮”、“是否选中”等属性; 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上的内容(联系人 和 电话号码) cell.textLabel.text = [contact getName]; cell.detailTextLabel.text = contact.phoneNumber; return cell; } #pragma mark 返回每组 头标题 名称 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ NSLog(@"生成组(组%li)名称",(long)section); KCContactGroup *group = contacts[section]; return group.name; } #pragma mark 返回每组 尾部 说明 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{ NSLog(@"生成尾部(组%li)详情",(long)section); KCContactGroup *group = contacts[section]; return group.detail; } #pragma mark 返回每组标题 索引 /** * 你们在使用iPhone通信录时会发现右侧能够按字母检索,使用起来很方便,其实这个功能使用UITableView实现很简单,只要实现数据源协议的一个方法,构建一个分组标题的数组便可实现。数组元素的内容和组标题内容未必彻底一致,UITableView是按照数组元素的索引和每组数据索引顺序来定位的而不是按内容查找。 */ - (nullable NSArray<NSString *> *)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 heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 45; } #pragma mark 设置分组标题内容高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ if (section == 0) { return 50; } return 40; } #pragma mark 设置尾部说明内容高度 - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ return 40; } #pragma mark 监听事件(点击会跳转,改值等) //在iOS中点击某联系我的就能够呼叫这个联系人,这时就须要监听点击操做,这里就不演示呼叫联系人操做了,咱们演示一下修改人员信息的操做。 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ selectedIndexPath = indexPath; KCContactGroup *group = contacts[indexPath.section]; KCContact *contact = group.contacts[indexPath.row]; NSLog(@"当前选中的组和行%@", selectedIndexPath); //建立弹出窗口 UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示" 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{ //当点击了第二个按钮(Ok) if (buttonIndex == 1) { UITextField *textField = [alertView textFieldAtIndex:0]; //修改模型数据 KCContactGroup *group = contacts[selectedIndexPath.section]; KCContact *contact = group.contacts[selectedIndexPath.row]; contact.phoneNumber = textField.text; // //刷新数据(---------------------------所有刷新--------------------) // [myTableView reloadData]; /** * 在上面的代码中咱们经过修改模型来改变UI显示,这种方式是经典的MVC应用,在后面的代码中会常常看到。固然UI的刷新使用了UITableView的reloadData方法,该方法会从新调用数据源方法,包括计算分组、计算每一个分组的行数,生成单元格等刷新整个UITableView。固然这种方式在实际开发中是不可取的,咱们不可能由于修改了一我的的信息就刷新整个UITableViewView,此时咱们须要采用局部刷新。局部刷新使用起来很简单,只须要调用UITableView的另一个方法 */ //刷新表格(----------------------局部刷新-------------------------) NSArray *indexPaths=@[selectedIndexPath];//须要局部刷新的单元格的组、行 [myTableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];//后面的参数表明更新时的动画 } } #pragma mark 重写状态样式方法 -(UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent; } #pragma mark 切换开关转化事件 -(void)switchValueChange:(UISwitch *)sw{ //打印点击的组 和 开关状态 NSLog(@"section:%li, switch:%i",(long)sw.tag,sw.on); } #pragma mark 删除按钮的方法 -(void)remove:(id)sender{ /** 在UITableView中不管是删除操做仍是添加操做都是经过修改UITableView的编辑状态来改变的(除非你不用UITableView自带的删除功能)。在删除按钮中咱们设置UITableView的编辑状态: */ //直接经过下面的方法设置编辑状态没有动画 //myTableView.editing=!myTableView.isEditing; //只要一句代码 //若是判断为假 isInsert=false; [myTableView setEditing:!myTableView.isEditing animated:true]; } #pragma mark 添加按钮的方法 -(void)add:(id)sender{ //只要一句代码 //若是判断为真 isInsert=true; [myTableView setEditing:!myTableView.isEditing animated:true]; } /** * 添加和删除操做都是设置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 编辑操做(删除和添加) /** * 用过iOS的朋友都知道,通常这种Cell若是向左滑动右侧就会出现删除按钮直接删除就能够了。其实实现这个功能只要实现代理-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;方法,只要实现了此方法向左滑动就会显示删除按钮。只要点击删除按钮这个方法就会调用,可是须要注意的是不管是删除仍是添加都是执行这个方法,只是第二个参数类型不一样。下面看一下具体的删除实现: */ //实现了此方法向左滑动就会显示删除(或添加)图标 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ KCContactGroup *group = contacts[indexPath.section]; KCContact *contact = group.contacts[indexPath.row]; /** * MVC的思想,要修改UI先修改数据。并且咱们看到了另外一个刷新表格的方法- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;,使用这个方法能够再删除以后刷新对应的单元格。 */ if (editingStyle == UITableViewCellEditingStyleDelete) { [group.contacts removeObject:contact]; //考虑到性能这里不建议使用reloadData // [myTableView reloadData]; //使用下面的方法,既能够局部刷新又有动画效果 [myTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; //若是当前组中没有数据,则移除刷新整个表格 if (group.contacts.count == 0) { [contacts removeObject:group]; [myTableView reloadData]; } }else if (editingStyle == UITableViewCellEditingStyleInsert){ KCContact *newContact = [[KCContact alloc]init]; newContact.firstName = @"xiao"; newContact.lastName = @"ming"; newContact.phoneNumber = @"888888888888"; [group.contacts insertObject:newContact atIndex:indexPath.row]; [myTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];//注意这里没有使用reloadData刷新 } } #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]; [myTableView reloadData]; } [destinationGroup.contacts insertObject:sourceContact atIndex:destinationIndexPath.row]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
须要注意的是上面几个重点方法的执行顺序,请看下图:
不少时候一个UIViewController中只有一个UITableView,所以苹果官方为了方便你们开发直接提供了一个UITableViewController,这个控制器 UITableViewController实现了UITableView数据源和代理协议,内部定义了一个tableView属性供外部访问,同时自动铺满整个屏幕、自动伸缩以方便咱们的开发。固然UITableViewController也并非简单的帮咱们定义完UITableView而且设置了数据源、代理而已,它还有其余强大的功能,例如刷新控件、滚动过程当中固定分组标题等。
有时候一个表格中的数据特别多,检索起来就显得麻烦,这个时候能够实现一个搜索功能帮助用户查找数据,其实搜索的原理很简单:修改模型、刷新表格。下面使用UITableViewController简单演示一下这个功能:
KCContactTableViewController.h
#import <UIKit/UIKit.h> @interface KCContactTableViewController : UITableViewController @end
KCContactTableViewController.m
#import "KCContactTableViewController.h" #import "KCContact.h" #import "KCContactGroup.h" #define kSearchbarHeight 44 @interface KCContactTableViewController ()<UISearchBarDelegate>{ UITableView *tableView; UISearchBar *mysearchBar; NSMutableArray *contacts;//联系人模型 NSMutableArray *searchContacts;//符合条件的搜索联系人 BOOL isSearching; } @end @implementation KCContactTableViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //添加搜索框 [self addSearchBar]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source #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; mysearchBar.text = @""; [self.tableView reloadData]; } #pragma mark 输入搜索关键字 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{ if ([mysearchBar.text isEqual:@""]) { isSearching = NO; [self.tableView reloadData]; return; } [self searchDataWithKeyWord:mysearchBar.text]; } #pragma mark 点击虚拟键盘上的搜索时 - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{ [self searchDataWithKeyWord:searchBar.text]; [mysearchBar resignFirstResponder];//放弃第一响应者对象,关闭虚拟键盘 } #pragma mark 重写状态样式方法 - (UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent; } #pragma mark 加载数据 - (void)initData{ contacts = [[NSMutableArray alloc]init]; KCContact *contact1 = [KCContact initWithFirstName:@"liu" andLastName:@"bo" andPhoneNumber:@"18811111111"]; KCContact *contact2 = [KCContact initWithFirstName:@"wang" andLastName:@"zhaohua" andPhoneNumber:@"18855555555"]; KCContactGroup *group1 = [KCContactGroup initWithName:@"jiaren" andDetail:@"womenshiyijiaren" andContacts:[NSMutableArray arrayWithObjects:contact1, contact2, nil]]; [contacts addObject:group1]; KCContact *contact3 = [KCContact initWithFirstName:@"zhang" andLastName:@"bing" andPhoneNumber:@"12345678900"]; KCContact *contact4 = [KCContact initWithFirstName:@"wu" andLastName:@"wei" andPhoneNumber:@"98765432100"]; KCContact *contact5 = [KCContact initWithFirstName:@"zhang" andLastName:@"san" andPhoneNumber:@"12345612345"]; KCContactGroup *group2 = [KCContactGroup initWithName:@"pengyou" andDetail:@"womenshipengyou" andContacts:[NSMutableArray arrayWithObjects:contact3, contact4, contact5, nil]]; [contacts addObject:group2]; KCContact *contact6 = [KCContact initWithFirstName:@"li" andLastName:@"si" andPhoneNumber:@"12345555555"]; KCContact *contact7 = [KCContact initWithFirstName:@"wang" andLastName:@"wu" andPhoneNumber:@"88888888888"]; KCContactGroup *group3 = [KCContactGroup initWithName:@"tongxue" andDetail:@"womenshitongxue" andContacts:[NSMutableArray arrayWithObjects:contact6, contact7, nil]]; [contacts addObject:group3]; KCContact *contact8 = [KCContact initWithFirstName:@"hi" andLastName:@"pi" andPhoneNumber:@"12345555555"]; KCContact *contact9 = [KCContact initWithFirstName:@"kang" andLastName:@"gu" andPhoneNumber:@"88888888888"]; KCContact *contact10 = [KCContact initWithFirstName:@"roi" andLastName:@"sfi" andPhoneNumber:@"12345555555"]; KCContact *contact11 = [KCContact initWithFirstName:@"fang" andLastName:@"ii" andPhoneNumber:@"88888888888"]; KCContact *contact12 = [KCContact initWithFirstName:@"tyng" andLastName:@"rd" andPhoneNumber:@"88888888888"]; KCContactGroup *group4 = [KCContactGroup initWithName:@"qinqi" andDetail:@"womenshiqinqi" andContacts:[NSMutableArray arrayWithObjects:contact8, contact9, contact10, contact11, contact12, nil]]; [contacts addObject:group4]; KCContact *contact13 = [KCContact initWithFirstName:@"roi" andLastName:@"sfi" andPhoneNumber:@"12345555555"]; KCContact *contact14 = [KCContact initWithFirstName:@"fang" andLastName:@"ii" andPhoneNumber:@"88888888888"]; KCContact *contact15 = [KCContact initWithFirstName:@"tyng" andLastName:@"rd" andPhoneNumber:@"88888888888"]; KCContactGroup *group5 = [KCContactGroup initWithName:@"tongshi" andDetail:@"womenshitongshi" andContacts:[NSMutableArray arrayWithObjects:contact13, contact14, contact15, nil]]; [contacts addObject:group5]; } #pragma mark 搜索造成新数据 - (void)searchDataWithKeyWord:(NSString *)keyWord{ isSearching = YES; searchContacts = [NSMutableArray array]; [contacts enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { KCContactGroup *group = obj; [group.contacts enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull 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, 44); mysearchBar = [[UISearchBar alloc]initWithFrame:searchBarRect]; mysearchBar.placeholder = @"请输入姓名";//浅色提示文字 mysearchBar.keyboardType = UIKeyboardTypeAlphabet;//键盘类型 mysearchBar.autocorrectionType = UITextAutocorrectionTypeNo;//自动纠错类型 mysearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;//哪一次shitf被自动按下 mysearchBar.showsCancelButton = YES;//显示取消按钮 //添加搜索框到页眉位置 mysearchBar.delegate = self; self.tableView.tableHeaderView = mysearchBar; } /* - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<#@"reuseIdentifier"#> forIndexPath:indexPath]; // Configure the cell... return cell; } */ /* // Override to support conditional editing of the table view. - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the specified item to be editable. return YES; } */ /* // Override to support editing the table view. - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete the row from the data source [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view } } */ /* // Override to support rearranging the table view. - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { } */ /* // Override to support conditional rearranging of the table view. - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the item to be re-orderable. return YES; } */ /* #pragma mark - Table view delegate // In a xib-based application, navigation from a table can be handled in -tableView:didSelectRowAtIndexPath: - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here, for example: // Create the next view controller. <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:<#@"Nib name"#> bundle:nil]; // Pass the selected object to the new view controller. // Push the view controller. [self.navigationController pushViewController:detailViewController animated:YES]; } */ /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
大神连接 - 很重要:
http://www.cnblogs.com/kenshincui/p/3931948.html#introduction
if ([tableView isEqual:leftTableView]) { static NSString *cellId = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId]; if (cell == nil) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId]; } cell.textLabel.text = @"陕西"; //选中cell后为紫色,对新生成的cell添加一个背景view:(将cell在选择时背景置为紫色) UIView *aVIew = [[UIView alloc]initWithFrame:cell.frame]; aVIew.backgroundColor = [UIColor purpleColor]; cell.selectedBackgroundView = aVIew; return cell; }