Objective-C UI之UITableView詳解

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的流程

  1. 當(dāng)一個(gè)Cell被滑出屏幕询微,這個(gè)Cell會(huì)被系統(tǒng)放到相應(yīng)的重用池中
  2. 當(dāng)tableView需要顯示一個(gè)Cell崖瞭,會(huì)先去重用池中嘗試獲取一個(gè)Cell
  3. 如果重用池沒有Cell,就會(huì)創(chuàng)建一個(gè)Cell
  4. 取得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

  1. 創(chuàng)建一個(gè)類繼承于UITableViewCell
  2. 實(shí)現(xiàn)UITableViewCell的初始化方法:- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
  3. 確保所有的添加的子視圖都在自定義Cell的初始化方法中創(chuàng)建甚疟,避免子視圖的重復(fù)創(chuàng)建
  4. 在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類而存在的
使用步驟:

  1. 創(chuàng)建一個(gè)Model類繼承于NSObject
  2. 添加和字典中對(duì)應(yīng)的屬性,屬性名要和字典key值相同挺尾,除系統(tǒng)關(guān)鍵字外
  3. 在視圖控制器中將字典通過KVC為Model賦值
  4. 將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è)定子視圖的高度

轉(zhuǎn)載請(qǐng)注明:作者SmithJackyson

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末果正,一起剝皮案震驚了整個(gè)濱河市炎码,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秋泳,老刑警劉巖潦闲,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異迫皱,居然都是意外死亡歉闰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門卓起,熙熙樓的掌柜王于貴愁眉苦臉地迎上來和敬,“玉大人,你說我怎么就攤上這事戏阅≈绲埽” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵饲握,是天一觀的道長(zhǎng)私杜。 經(jīng)常有香客問我,道長(zhǎng)救欧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任锣光,我火速辦了婚禮笆怠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘誊爹。我一直安慰自己蹬刷,他們只是感情好瓢捉,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著办成,像睡著了一般泡态。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上迂卢,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天某弦,我揣著相機(jī)與錄音,去河邊找鬼而克。 笑死靶壮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的员萍。 我是一名探鬼主播腾降,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼碎绎!你這毒婦竟也來了螃壤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤筋帖,失蹤者是張志新(化名)和其女友劉穎奸晴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體幕随,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚁滋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赘淮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辕录。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梢卸,靈堂內(nèi)的尸體忽然破棺而出走诞,到底是詐尸還是另有隱情,我是刑警寧澤蛤高,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布蚣旱,位于F島的核電站,受9級(jí)特大地震影響戴陡,放射性物質(zhì)發(fā)生泄漏塞绿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一恤批、第九天 我趴在偏房一處隱蔽的房頂上張望异吻。 院中可真熱鬧,春花似錦、人聲如沸诀浪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雷猪。三九已至睛竣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間求摇,已是汗流浹背射沟。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留月帝,地道東北人躏惋。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嚷辅,于是被迫代替她去往敵國和親簿姨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容