背景知识
每个表都是UITableView的实例,表中的每一行都是UITableViewCell的实例。
TableView的种类
- Grouped table
- Plain table without index
- Plain table with index
NSIndexPath
- NSIndexPath.section 返回int,表示第几个Section
- NSIndexPath.row 返回int,表示该Section下的第几行
UITableViewCell包含的元素
- Image (imageView.image)
- Text Label (textLabel.text, textLabel.font)
- Detail Text Label (detailTextLabel.text)
UITableViewCell样式
- UITableViewCellStyleDefault //左文,图(如果有则最左)
- UITableViewCellStyleSubtitile //左文,图(如果有则最左),detailText在Text下面
- UITableViewCellStyleValue1 //左文,图(如果有则最左),detailText在最右
- UITableViewCellStyleValue2 //左文,图(如果有则最左),detailText在Text右边
简单例子
StoryBoard拖入一个TableView,然后设置DataSource和Delegate为ViewController。
ViewController.h声明协议
#import <UIKit/UIKit.h> @interface XYZViewController : UIViewController<UITableViewDataSource, UITableViewDelegate> @end
ViewController.m文件如下
// // XYZViewController.m // TableView // // Created by Norcy on 14-7-24. // Copyright (c) 2014年 QQLive. All rights reserved. // #import "XYZViewController.h" @interface XYZViewController () @property (strong, nonatomic)NSArray *array; @end @implementation XYZViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.array = [[NSArray alloc] initWithObjects:@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", @"12", @"13", @"14", @"15", nil]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - #pragma mark Data Source Methods - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.array count]; } #pragma mark Delegate Methods - (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellId = @"MyCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellId]; } cell.textLabel.text = self.array[indexPath.row]; UIImage *image = [UIImage imageNamed:@"1.png"]; cell.imageView.image = image; cell.detailTextLabel.text = @"Details"; return cell; } - (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath { return indexPath.row; } @end
代码说明
代码说明1:
static NSString *CellID = @"MyCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID]; }
从ReusableCell的队列中取出带有Identifier标识的Cell,如果Cell为空,则新创建一个。
ReusableCell队列是专门存放那些生成过的,但是后来由于滚动tableView而隐藏起来的cell。这样做可以节约资源。
注意CellIdentifier这个参数是可以自定义的,如果使用storyboard的话需要跟storyboard中的cell的Identifier相同。
- dequeueReusableCellWithIdentifier: 可能返回nil(没有为TableView注册Cell的情况返回nil)
- dequeueReusableCellWithIdentifier:forIndexPath: 不可能返回nil
所以如果使用dequeueReusableCellWithIdentifier:forIndexPath的话就不用检查nil的情况了。
But,以上这种写法已经过时了。推荐最新写法
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CELL_ID];
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID forIndexPath:indexPath];
如果TableView已经注册了Cell,那么dequeueReusableCellWithIdentifier:一定不为空;因为当系统从重用队列中取cell取不到的时候,会自动帮我们生成并初始化一个cell。
所以建议直接用registerClass:forCellReuseIdentifier:CELL_ID + dequeueReusableCellWithIdentifier:forIndexPath: 这个组合。
代码说明2:
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath { return indexPath.row;
}
设置缩进。
代码说明3:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) return nil; else return indexPath; }
选中某行之前调用,返回nil表示该行不能被选择,返回indexPath表示可以继续选择(可以返回其他路径但最好不要更改用户的选择,所以一般返回nil或indexPath来表示禁止或允许某个选择)
代码说明4:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; }
选中某行之后调用,一般要调用deselectRowAtIndexPath
代码说明5:
cell.textLabel.font = [UIFont boldSystemFontOfSize:50]; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 70; }
设置TableViewCell的行高以适应TableViewCell的字体
附录,联系人Demo(Based in IOS7.0) or 直接查看主要代码
// // ViewController.m // Contact // // Created by Norcy on 15/4/16. // Copyright (c) 2015年 Norcy. All rights reserved. // #import "ViewController.h" @interface ViewController () { } @property (strong, nonatomic) NSDictionary* names; @property (strong, nonatomic) NSArray* keys; @end NSMutableArray* filteredNames; UISearchDisplayController* searchController; static NSString* CELL_ID = @"MyCell"; @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //Screen int screenWidth = [[UIScreen mainScreen] bounds].size.width; int screenHeight = [[UIScreen mainScreen] bounds].size.height; //Filter filteredNames = [[NSMutableArray alloc] init]; //TableView UITableView* tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)]; [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CELL_ID]; tableView.delegate = self; tableView.dataSource = self; tableView.tag = 1; UIEdgeInsets insets = tableView.contentInset; //设置与屏幕顶部的距离,防止被状态栏挡住 insets.top = 20; [tableView setContentInset:insets]; //Search Bar UISearchBar* searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight / 12)]; tableView.tableHeaderView = searchBar; searchController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self]; searchController.delegate = self; searchController.searchResultsDataSource = self; //Names and Keys NSString* path = [[NSBundle mainBundle] pathForResource:@"sortednames" ofType:@"plist"]; self.names = [NSDictionary dictionaryWithContentsOfFile:path]; self.keys = [[self.names allKeys] sortedArrayUsingSelector:@selector(compare:)]; [self.view addSubview:tableView]; } #pragma mark - #pragma mark Data Source Methods - (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView { if (tableView.tag == 1) return [self.keys count]; else return 1; } - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { if (tableView.tag == 1) { NSString* key = self.keys[section]; NSArray* curSection = self.names[key]; return [curSection count]; } else return [filteredNames count]; } - (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section { if (tableView.tag == 1) return self.keys[section]; else return nil; } - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID forIndexPath:indexPath]; // UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID]; // if (cell == nil) // { // NSLog(@"asd"); // cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CELL_ID]; // } if (tableView.tag == 1) { NSString* key = self.keys[indexPath.section]; NSArray* curSection = self.names[key]; cell.textLabel.text = curSection[indexPath.row]; } else cell.textLabel.text = filteredNames[indexPath.row]; return cell; } #pragma mark Delegate Methods //显示索引 - (NSArray*)sectionIndexTitlesForTableView:(UITableView*)tableView { if (tableView.tag == 1) return self.keys; else return nil; } - (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; } #pragma mark Search Delegate Methods - (void)searchDisplayController:(UISearchDisplayController*)controller didLoadSearchResultsTableView:(UITableView*)tableView { [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CELL_ID]; } - (BOOL)searchDisplayController:(UISearchDisplayController*)controller shouldReloadTableForSearchString:(NSString*)searchString { [filteredNames removeAllObjects]; if (searchString.length > 0) { NSPredicate* predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary* bindings) { NSRange range = [evaluatedObject rangeOfString:searchString options:NSCaseInsensitiveSearch]; return range.location != NSNotFound; }]; for (NSString* key in self.keys) { NSArray* matches = [self.names[key] filteredArrayUsingPredicate:predicate]; [filteredNames addObjectsFromArray:matches]; } } return YES; } @end