UITableView在iOS開發(fā)中占據(jù)非常重要的位置护奈,必須熟練掌握。
學(xué)習(xí)UITableView之前蕾管,先了解一下一些基本概念:
- UITableView繼承于UIScrollView事镣,是可以進(jìn)行垂直滾動(dòng)的控件
- UITableView的每一條數(shù)據(jù)對(duì)應(yīng)的單元格叫做Cell,是UITableViewCell的一個(gè)對(duì)象逻住,繼承于UIView
- UITableView可以分區(qū)顯示,每一個(gè)分區(qū)稱為section迎献,每一行稱為row,編號(hào)都從0開始
- 系統(tǒng)提供了一個(gè)類來整合section和row腻贰,叫做NSIndexPath
從上面可以了解到,section和row代表一個(gè)UITableViewCell在UITableView上的位置
下面,我們創(chuàng)建一個(gè)UITableView:
//style是一個(gè)UITableViewStyle類型的參數(shù)蕴掏,是一個(gè)枚舉類型贯底,包含UITableViewStylePlain,UITableViewStyleGrouped
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
[self.view addSubview:tableView];
下面是UITableView的常用屬性:
rowHeight 行高
separatorStyle 分隔線樣式
separatorColor 分隔線顏色
tableHeaderView UITableView的置頂視圖
tableFooterView UITableView置底視圖
一、UITableView基礎(chǔ)
UITableView中有兩個(gè)重要的屬性:dataSource(遵循UITableViewDataSource協(xié)議)和delegate(遵循UITableViewDelegate協(xié)議)
其中dataSource是和顯示數(shù)據(jù)相關(guān)的代理写烤,delegate是和視圖操作相關(guān)的代理
UITableViewDataSource協(xié)議中有兩個(gè)必須實(shí)現(xiàn)的協(xié)議方法:
1.UITableView每個(gè)分區(qū)包含的行數(shù):
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
2.每一行要顯示的Cell: - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
第一個(gè)方法可以根據(jù)給出的參數(shù)section不同返回不同的行數(shù)
第二個(gè)方法:tableView每次要顯示一個(gè)Cell都會(huì)調(diào)用這個(gè)方法獲取
UITableView的每一個(gè)單元格是UITableViewCell類的對(duì)象翼闽,默認(rèn)提供了三個(gè)視圖屬性:
- 圖片視圖:UIImageView *imageView
- 標(biāo)題視圖:UILabel *textLabel
- 副標(biāo)題視圖:UILabel *detailTextLabel
下面是返回Cell的例子:(沒有使用registerClass注冊(cè)的情況)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"cell";
//通過標(biāo)識(shí)符,在tableView的重用池中找到可用的Cell(在重用池內(nèi)部其實(shí)是一個(gè)可變的集合)
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
//如果重用池中沒有這個(gè)標(biāo)識(shí)符對(duì)應(yīng)的cell洲炊,則創(chuàng)建一個(gè)新的感局,并且設(shè)置標(biāo)識(shí)符
if (!cell) {
//代碼塊內(nèi)只做Cell樣式的處理尼啡,不做數(shù)據(jù)設(shè)置
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:cellID];
}
//對(duì)Cell做數(shù)據(jù)設(shè)置
[cell.textLabel setText:@"標(biāo)題"];
[cell.detailTextLabel setText:@"描述:這是小標(biāo)題"];
return cell;
}
UITableView有一個(gè)重用池機(jī)制管理Cell,目的是使用盡可能少的Cell顯示所有的數(shù)據(jù)
UITableView重用Cell的流程
- 當(dāng)一個(gè)Cell被滑出屏幕询微,這個(gè)Cell會(huì)被系統(tǒng)放到相應(yīng)的重用池中
- 當(dāng)tableView需要顯示一個(gè)Cell崖瞭,會(huì)先去重用池中嘗試獲取一個(gè)Cell
- 如果重用池沒有Cell,就會(huì)創(chuàng)建一個(gè)Cell
- 取得Cell之后會(huì)重新賦值進(jìn)行使用
在創(chuàng)建UITableView之后撑毛,需要注冊(cè)一個(gè)Cell類书聚,當(dāng)重用池中沒有Cell的時(shí)候,系統(tǒng)可以自動(dòng)創(chuàng)建Cell藻雌。相關(guān)方法:
[tableView registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier];(可以使用不同identifier進(jìn)行多次注冊(cè))
系統(tǒng)提供了一個(gè)獲取重用池中Cell的方法(需要一個(gè)重用標(biāo)識(shí)):
- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
UITableView的常用協(xié)議方法
1.UITableViewDataSource
- UITableView分區(qū)個(gè)數(shù):
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- 分區(qū)的頂部標(biāo)題:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
- 分區(qū)的底部標(biāo)題:
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
- UITableView右側(cè)的索引錄:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
2.UITableViewDelegate
- 告訴delegate選中了一個(gè)Cell:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- 每一行的高度:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
- 每一個(gè)分區(qū)的頂部高度:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
- 每一個(gè)分區(qū)的頂部自定義視圖:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
二雌续、UITableView編輯
流程:
- 讓tableView處于編輯狀態(tài):[tableView setEditing:(BOOL)editing animated:(BOOL)animated];
- 確定Cell是否處于編輯狀態(tài):
//重寫UITableViewDataSource的協(xié)議方法,根據(jù)indexPath決定哪些Cell處于編輯狀態(tài)胯杭,返回YES是可編輯西雀,NO為不可編輯
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
- 設(shè)定Cell的編輯樣式(刪除、添加):
//重寫UITableViewDelegate的協(xié)議方法歉摧,根據(jù)indexPath可以決定Cell的編輯樣式艇肴,是添加UITableViewCellEditingStyleInsert還是刪除UITableViewCellEditingStyleDelete,還是不進(jìn)行編輯UITableViewCellEditingStyleNone
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
- 編輯狀態(tài)進(jìn)行提交:
//重寫UITableViewDataSource協(xié)議方法叁温,根據(jù)editingStyle刪除indexPath位置的Cell再悼,還是在indexPath處插入Cell,修改數(shù)據(jù)源
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
注意:編輯結(jié)束后膝但,由于numberOfRowInSection這個(gè)協(xié)議方法只在tableView添加到父視圖的時(shí)候調(diào)用一次冲九,而且table上的數(shù)據(jù)都是由數(shù)組提供,因此跟束,需要先改變數(shù)組中的數(shù)據(jù)莺奸,然后讓table的協(xié)議重新調(diào)用進(jìn)行重新賦值
即先修改數(shù)據(jù)源,在刷新table(使用[table reloadData]方法刷新)
三冀宴、UITableView移動(dòng)
- 實(shí)現(xiàn)協(xié)議灭贷,告訴tableView是否能夠移動(dòng):
//返回YES允許移動(dòng)
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
- 移動(dòng):
//修改數(shù)據(jù)源,再進(jìn)行[tableView reloadData]更新tableView視圖數(shù)據(jù)
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
四略贮、UITableViewCell
1.自定義Cell
- 創(chuàng)建一個(gè)類繼承于UITableViewCell
- 實(shí)現(xiàn)UITableViewCell的初始化方法:- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
- 確保所有的添加的子視圖都在自定義Cell的初始化方法中創(chuàng)建甚疟,避免子視圖的重復(fù)創(chuàng)建
- 在Cell的子視圖創(chuàng)建成功后,將子視圖設(shè)置為屬性逃延,便于在UITableView的協(xié)議中給自定義視圖賦值
一般而言览妖,Cell在創(chuàng)建的時(shí)候的frame大小是(0,0,320,44),而我們?cè)O(shè)定的Cell的高度一般會(huì)大于44揽祥。因此:在自定義Cell中創(chuàng)建子視圖的frame為CGRectZero讽膏。在Cell添加到tableView上的時(shí)候才給子視圖設(shè)置frame,Cell添加到tableView的時(shí)候大小已經(jīng)更改為tableView設(shè)定的大小拄丰,所以在自定義Cell的方法layoutSubviews中設(shè)置子視圖的frame
2.Model的使用
Model類的作用主要是為我們提供數(shù)據(jù)府树,一般我們的數(shù)據(jù)都是存放在數(shù)組和字典中俐末,OC中的KVC就是幫助我們將字典轉(zhuǎn)換為Model類而存在的
使用步驟:
- 創(chuàng)建一個(gè)Model類繼承于NSObject
- 添加和字典中對(duì)應(yīng)的屬性,屬性名要和字典key值相同挺尾,除系統(tǒng)關(guān)鍵字外
- 在視圖控制器中將字典通過KVC為Model賦值
- 將Model對(duì)象添加到數(shù)組中并刷新tableView
注意:Model類要重寫-(void)setValue:(id)value forUndefinedKey:(NSString *)key鹅搪,防止找不到和key值相同的屬性時(shí),會(huì)crash遭铺,當(dāng)key值為系統(tǒng)關(guān)鍵字丽柿,可以在方法里面為對(duì)應(yīng)的屬性(屬性名和系統(tǒng)關(guān)鍵字不沖突)賦值,比如_id = value;
3.多種Cell混合使用
不同的Cell需要使用不同的重用標(biāo)識(shí)符來進(jìn)行區(qū)分魂挂,而重用標(biāo)識(shí)符的區(qū)分需要根據(jù)不同的情況來區(qū)分甫题,比如:
- Model屬性區(qū)分(不同的數(shù)據(jù)內(nèi)容,比如數(shù)據(jù)中有type字段涂召,0代表文字類型坠非,1代表圖片類型)
- 固定的行顯示的Cell類型不一樣
4.自適應(yīng)高度
- 文本自適應(yīng)高度:
//獲得字體樣式屬性
NSDictionary *att = @{NSFontAttributeName:[UIFont systemFontOfSize:18.0]};
//根據(jù)字體樣式屬性獲得高度
CGRect rect = [string boundingRectWithSize:CGSizeMake(300,MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:att context:nil];
//重新設(shè)置顯示文本控件的frame
[self.label setFrame:CGRectMake(0,0,300,rect.size.height)];
//我們可以定義一個(gè)類專門用來計(jì)算文本高度,這樣可以使用時(shí)直接調(diào)用
- Cell自適應(yīng)高度:
通過協(xié)議方法- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath設(shè)定Cell的高度
在自定義Cell中的layoutSubviews方法中設(shè)定子視圖的高度