UITableView的數(shù)據(jù)源(dataSource)和代理(delegate)
UITableView需要一個(gè)數(shù)據(jù)源(dataSource)來顯示數(shù)據(jù),UITableView會(huì)向數(shù)據(jù)源查詢一共有多少行數(shù)據(jù)以及每一行顯示什么數(shù)據(jù)等。沒有設(shè)置數(shù)據(jù)源的UITableView只是個(gè)空殼肛循。凡是遵守UITableViewDataSource協(xié)議的OC對(duì)象,都可以是UITableView的數(shù)據(jù)源银择。
通常都要為UITableView設(shè)置代理對(duì)象(delegate)多糠,以便在UITableView觸發(fā)一下事件時(shí)做出相應(yīng)的處理,比如選中了某一行浩考。凡是遵守了UITableViewDelegate協(xié)議的OC對(duì)象夹孔,都可以是UITableView的代理對(duì)象。一般會(huì)讓控制器充當(dāng)UITableView的dataSource和delegate
UITableViewDataSource
@required
-?(NSInteger)tableView:(UITableView?*)tableView?numberOfRowsInSection:(NSInteger)section;
第section分區(qū)一共有多少行
-?(UITableViewCell?*)tableView:(UITableView?*)tableViewcellForRowAtIndexPath:(NSIndexPath?*)indexPath;
創(chuàng)建第section分區(qū)第row行的UITableViewCell對(duì)象(indexPath包含了section和row)
@optional
-?(NSInteger)numberOfSectionsInTableView:(UITableView?*)tableView;
一共有多少個(gè)分區(qū)
-?(NSString?*)tableView:(UITableView?*)tableView?titleForHeaderInSection:(NSInteger)section;
第section分區(qū)的頭部標(biāo)題
-?(NSString?*)tableView:(UITableView?*)tableView?titleForFooterInSection:(NSInteger)section;
第section分區(qū)的底部標(biāo)題
-?(BOOL)tableView:(UITableView?*)tableView?canEditRowAtIndexPath:(NSIndexPath?*)indexPath;
某一行是否可以編輯(刪除)
-?(BOOL)tableView:(UITableView?*)tableView?canMoveRowAtIndexPath:(NSIndexPath?*)indexPath;
某一行是否可以移動(dòng)來進(jìn)行重新排序
-?(NSArray?*)sectionIndexTitlesForTableView:(UITableView?*)tableView;
UITableView右邊的索引欄的內(nèi)容
-?(void)tableView:(UITableView?*)tableView?didSelectRowAtIndexPath:(NSIndexPath?*)indexPath
選中了UITableView的某一行
-?(CGFloat)tableView:(UITableView?*)tableView?heightForRowAtIndexPath:(NSIndexPath?*)indexPath
某一行的高度
-?(CGFloat)tableView:(UITableView?*)tableView?heightForHeaderInSection:(NSInteger)section
第section分區(qū)頭部的高度
-?(CGFloat)tableView:(UITableView?*)tableView?heightForFooterInSection:(NSInteger)section
第section分區(qū)尾部的高度
-?(UIView?*)tableView:(UITableView?*)tableView?viewForHeaderInSection:(NSInteger)section
第section分區(qū)頭部顯示的視圖
-?(UIView?*)tableView:(UITableView?*)tableView?viewForFooterInSection:(NSInteger)section
第section分區(qū)尾部顯示的視圖
-?(NSInteger)tableView:(UITableView?*)tableViewindentationLevelForRowAtIndexPath:(NSIndexPath?*)indexPath
設(shè)置每一行的等級(jí)縮進(jìn)(數(shù)字越小析孽,等級(jí)越高)
UITableViewCell
UITableView的每一行都是一個(gè)UITableViewCell,通過dataSource的
tableView:cellForRowAtIndexPath:方法來初始化每一行
UITableViewCell是UIView的子類搭伤,內(nèi)部有個(gè)默認(rèn)的子視圖:contentView。contentView是UITableViewCell所顯示內(nèi)容的父視圖袜瞬,并負(fù)責(zé)顯示一些輔助指示視圖怜俐。輔助指示視圖的作用是顯示一個(gè)表示動(dòng)作的圖標(biāo),可以通過設(shè)置UITableViewCell的accessoryType來顯示邓尤,默認(rèn)是UITableViewCellAccessoryNone(不顯示輔助指示視圖)拍鲤,其他值如下:
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryCheckmark
UITableViewCell的contentView
contentView下默認(rèn)有3個(gè)子視圖,其中的2個(gè)是UILabel(通過UITableViewCell的textLabel和detailTextLabel屬性訪問)汞扎,第3個(gè)是UIImageView(通過UITableViewCell的imageView屬性訪問)
UITableViewCell還有一個(gè)UITableViewCellStyle屬性季稳,用于決定使用contentView的哪些子視圖,以及這些子視圖在contentView中的位置
UITableViewCell對(duì)象的重用原理
iOS設(shè)備的內(nèi)存有限澈魄,如果用UITableView顯示成千上萬條數(shù)據(jù)绞幌,就需要成千上萬個(gè)UITableViewCell對(duì)象的話,那將會(huì)耗盡iOS設(shè)備的內(nèi)存一忱。要解決該問題,需要重用UITableViewCell對(duì)象
重用原理:當(dāng)滾動(dòng)列表時(shí)谭确,部分UITableViewCell會(huì)移出窗口帘营,UITableView會(huì)將窗口外的UITableViewCell放入一個(gè)對(duì)象池中,等待重用逐哈。當(dāng)UITableView要求dataSource返回UITableViewCell時(shí)芬迄,dataSource會(huì)先查看這個(gè)對(duì)象池,如果池中有未使用的UITableViewCell昂秃,dataSource會(huì)用新的數(shù)據(jù)配置這個(gè)UITableViewCell禀梳,然后返回給UITableView杜窄,重新顯示到窗口中,從而避免創(chuàng)建新對(duì)象
還有一個(gè)非常重要的問題:有時(shí)候需要自定義UITableViewCell(用一個(gè)子類繼承UITableViewCell)算途,而且每一行用的不一定是同一種UITableViewCell(如短信聊天布局)塞耕,所以一個(gè)UITableView可能擁有不同類型的UITableViewCell,對(duì)象池中也會(huì)有很多不同類型的UITableViewCell嘴瓤,那么UITableView在重用UITableViewCell時(shí)可能會(huì)得到錯(cuò)誤類型的UITableViewCell
解決方案:UITableViewCell有個(gè)NSString?*reuseIdentifier屬性扫外,可以在初始化UITableViewCell的時(shí)候傳入一個(gè)特定的字符串標(biāo)識(shí)來設(shè)置reuseIdentifier(一般用UITableViewCell的類名)。當(dāng)UITableView要求dataSource返回UITableViewCell時(shí)廓脆,先通過一個(gè)字符串標(biāo)識(shí)到對(duì)象池中查找對(duì)應(yīng)類型的UITableViewCell對(duì)象筛谚,如果有,就重用停忿,如果沒有驾讲,就傳入這個(gè)字符串標(biāo)識(shí)來初始化一個(gè)UITableViewCell對(duì)象
重用UITableViewCell對(duì)象
-?(UITableViewCell?*)tableView:(UITableView?*)tableViewcellForRowAtIndexPath:(NSIndexPath?*)indexPath
{
static?NSString?*identifier?=?@"UITableViewCell";
UITableViewCell?*cell?=?[tableView?dequeueReusableCellWithIdentifier:identifier];
if?(cell?==?nil)?{
cell?=?[[[UITableViewCell?alloc]?initWithStyle:UITableViewCellStyleDefault?reuseIdentifier:identifier]?autorelease];
}
cell.textLabel.text?=?[NSString?stringWithFormat:@"Text?%i",?indexPath.row];
return?cell;
}
UITableViewCell的常用屬性
設(shè)置背景
backgroundView
設(shè)置被選中時(shí)的背景視圖
selectedBackgroundView
selectionStyle屬性可設(shè)置UITableViewCell被選中時(shí)的背景顏色:
UITableViewCellSelectionStyleNone沒有顏色
UITableViewCellSelectionStyleBlue藍(lán)色(默認(rèn))
UITableViewCellSelectionStyleGray灰色
自定義UITableViewCell
一般有兩種方式:
用一個(gè)xib文件來描述UITableViewCell的內(nèi)容
通過代碼往UITableViewCell的contentView中添加子視圖,在初始化方法(比如init席赂、initWithStyle:reuseIdentifier:)中添加子控件吮铭,在layoutSubviews方法中分配子控件的位置和大小
UITableView的編輯模式
UITableView有個(gè)editing屬性,設(shè)置為YES時(shí)氧枣,可以進(jìn)入編輯模式沐兵。在編輯模式下,可以管理表格中的行便监,比如改變行的排列順序扎谎、增加行、刪除行烧董,但不能修改行的內(nèi)容
多種方式開啟編輯模式
@property(nonatomic,getter=isEditing)?BOOL?editing
-?(void)setEditing:(BOOL)editing?animated:(BOOL)animated
刪除UITableView的行
首先要開啟編輯模式
實(shí)現(xiàn)UITableViewDataSource的如下方法:
-?(void)tableView:(UITableView?*)tableViewcommitEditingStyle:(UITableViewCellEditingStyle)editingStyle?forRowAtIndexPath:(NSIndexPath?*)indexPath
{
//如果UITableView提交的是刪除指令
if?(editingStyle?==?UITableViewCellEditingStyleDelete)?{
//刪除真實(shí)數(shù)據(jù)
//?[self.data?removeObjectAtIndex:indexPath.row];
//刪除UITableView中的某一行(帶動(dòng)畫效果)
[tableView?deleteRowsAtIndexPaths:[NSArray?arrayWithObject:indexPath]?withRowAnimation:UITableViewRowAnimationLeft];
//如果不考慮動(dòng)畫效果毁靶,也可以直接[tableView?reload];
}
}
移動(dòng)UITableView的行
首先要開啟編輯模式
實(shí)現(xiàn)UITableViewDataSource的如下方法(如果沒有實(shí)現(xiàn)此方法,將無法換行)
-?(void)tableView:(UITableView?*)tableView?moveRowAtIndexPath:(NSIndexPath*)sourceIndexPath?toIndexPath:(NSIndexPath?*)destinationIndexPath
{
int?from?=?sourceIndexPath.row;
int?to?=?destinationIndexPath.row;
if?(from?==?to)?return;
//交換數(shù)據(jù)
//?[self.data?exchangeObjectAtIndex:from?withObjectAtIndex:to];
}
選中UITableView的行
當(dāng)某行被選中時(shí)會(huì)調(diào)用此方法(UITableViewDelegate的方法)
-?(void)tableView:(UITableView?*)tableView?didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
//取消選中某一行,讓被選中行的高亮顏色消失(帶動(dòng)畫效果)
[tableView?deselectRowAtIndexPath:indexPath?animated:YES];
}
UITableView常用方法
-?(id)initWithFrame:(CGRect)frame?style:(UITableViewStyle)style
初始化一個(gè)UITableView逊移,并且設(shè)置表格樣式
-?(void)reloadData重新訪問數(shù)據(jù)源预吆,刷新界面
-?(NSInteger)numberOfSections分區(qū)的個(gè)數(shù)
-?(NSInteger)numberOfRowsInSection:(NSInteger)section
第section分區(qū)的行數(shù)
-?(UITableViewCell?*)cellForRowAtIndexPath:(NSIndexPath?*)indexPath
通過indexPath找到對(duì)應(yīng)的UITableViewCell對(duì)象
-?(void)setEditing:(BOOL)editing?animated:(BOOL)animated
是否要開啟編輯模式
-?(void)deselectRowAtIndexPath:(NSIndexPath?*)indexPath?animated:(BOOL)animated
取消選中某一行,讓被選中行的高亮顏色消失(帶動(dòng)畫效果)
-?(id)dequeueReusableCellWithIdentifier:(NSString?*)identifier
通過identifier在(緩存)池中找到對(duì)應(yīng)的UITableViewCell對(duì)象
-?(void)deleteRowsAtIndexPaths:(NSArray?*)indexPathswithRowAnimation:(UITableViewRowAnimation)animation
移除indexPaths范圍內(nèi)的所有行
@property(nonatomic,readonly)?UITableViewStyle?style表格樣式
@property(nonatomic,assign)?id??dataSource
數(shù)據(jù)源
@property(nonatomic,assign)?id??delegate代理
@property(nonatomic,getter=isEditing)?BOOL?editing是否為編輯模式
@property(nonatomic)?UITableViewCellSeparatorStyle?separatorStyle
設(shè)置分隔線的樣式
@property(nonatomic,retain)?UIColor?*separatorColor
設(shè)置分隔線的顏色
@property(nonatomic,retain)?UIView?*tableHeaderView
表頭顯示的視圖
@property(nonatomic,retain)?UIView?*tableFooterView
表尾顯示的視圖
@property(nonatomic)?BOOL?allowsSelection
是否允許選中行
@property(nonatomic)?BOOL?allowsSelectionDuringEditing
是否允許在編輯模式下選中行
@property(nonatomic)?BOOL?allowsMultipleSelection
是否允許選中多行
@property(nonatomic)?BOOL?allowsMultipleSelectionDuringEditing
是否允許在編輯模式下選中多行
UITableViewController
是UIViewController的子類,UITableViewController默認(rèn)扮演了3種角色:視圖控制器胳泉、UITableView的數(shù)據(jù)源和代理
UITableViewController的view是個(gè)UITablView,由UITableViewController負(fù)責(zé)設(shè)置和顯示這個(gè)對(duì)象拐叉。UITableViewController對(duì)象被創(chuàng)建后,會(huì)將這個(gè)UITableView對(duì)象的dataSource和delegate指向UITableViewController自己
一扇商、UITableView
1.數(shù)據(jù)展示的條件
1>?UITableView的所有數(shù)據(jù)都是由數(shù)據(jù)源(dataSource)提供的凤瘦,所以要想在UITableView展示數(shù)據(jù),必須設(shè)置UITableView的dataSource數(shù)據(jù)源對(duì)象
2>要想當(dāng)UITableView的dataSource對(duì)象案铺,必須遵守UITableViewDataSource協(xié)議蔬芥,實(shí)現(xiàn)相應(yīng)的數(shù)據(jù)源方法
3>當(dāng)UITableView想要展示數(shù)據(jù)的時(shí)候,就會(huì)給數(shù)據(jù)源發(fā)送消息(調(diào)用數(shù)據(jù)源方法),UITableView會(huì)根據(jù)方法返回值決定展示怎樣的數(shù)據(jù)
2.數(shù)據(jù)展示的過程
1>先調(diào)用數(shù)據(jù)源的
-?(NSInteger)numberOfSectionsInTableView:(UITableView?*)tableView
得知一共有多少組
2>然后調(diào)用數(shù)據(jù)源的
-?(NSInteger)tableView:(UITableView?*)tableView?numberOfRowsInSection:(NSInteger)section
得知第section組一共有多少行
3>然后調(diào)用數(shù)據(jù)源的
-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath
得知第indexPath.section組?第indexPath.row行顯示怎樣的cell(顯示什么內(nèi)容)
3.常見數(shù)據(jù)源方法
1>一共有多少組
-?(NSInteger)numberOfSectionsInTableView:(UITableView?*)tableView
2>第section組一共有多少行
-?(NSInteger)tableView:(UITableView?*)tableView?numberOfRowsInSection:(NSInteger)section
3>第indexPath.section組?第indexPath.row行顯示怎樣的cell(顯示什么內(nèi)容)
-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath
4>第section組顯示怎樣的頭部標(biāo)題
-?(NSString?*)tableView:(UITableView?*)tableView?titleForHeaderInSection:(NSInteger)section;
5>第section組顯示怎樣的尾部標(biāo)題
-?(NSString?*)tableView:(UITableView?*)tableView?titleForFooterInSection:(NSInteger)section;
4.tableView刷新數(shù)據(jù)的方式
1>修改模型數(shù)據(jù)
2>刷新表格
*?reloadData整體刷新(每一行都會(huì)刷新)
*?-?(void)reloadRowsAtIndexPaths:(NSArray?*)indexPathswithRowAnimation:(UITableViewRowAnimation)animation
局部刷新
5.性能優(yōu)化
1>定義一個(gè)循環(huán)利用標(biāo)識(shí)
static?NSString?*ID?=?@"C1";
2>從緩存池中取出可循環(huán)利用的cell
UITableViewCell?*cell?=?[tableView?dequeueReusableCellWithIdentifier:ID];
3>如果緩存池中沒有可循環(huán)利用的cell
if?(cell?==?nil)
{
cell?=?[[UITableViewCell?alloc]?initWithStyle:UITableViewCellStyleDefault?reuseIdentifier:ID];
}
4>覆蓋cell上面的數(shù)據(jù)
cell.textLabel.text?=?[NSString?stringWithFormat:@"第%d行數(shù)據(jù)",?indexPath.row];
步驟一:創(chuàng)建UITableView笔诵。UITableView樣式為組
步驟二:設(shè)置UITableView的數(shù)據(jù)源方法返吻。
步驟三:實(shí)現(xiàn)UITableView的數(shù)據(jù)源方法,此方法會(huì)自動(dòng)調(diào)用乎婿。
返回有多少組
返回一組有多少行
返回每一行顯示的UITableViewCell(繼承UIView),initWithStyle使用這個(gè)方法調(diào)用测僵。
注意UITableView的數(shù)據(jù)源的方法普遍都是以tableView開頭。
步驟四:用數(shù)組管理數(shù)據(jù)次酌。
步驟五:每個(gè)數(shù)組中都是一個(gè)字典恨课,key:(header,footer,cityes).
3.擴(kuò)展性好:指的是需求改了,代碼不需要怎么改岳服。
4.創(chuàng)建模型的時(shí)候剂公,自定義一個(gè)工廠方法(類方法)接口給外界調(diào)用。
工廠方法好處:簡(jiǎn)化對(duì)象的實(shí)例化吊宋,快速創(chuàng)建對(duì)象纲辽。
UITableViewCellStyleDefault
UITableViewCellStyleValue1
UITableViewCellStyleSubtitle
UITableViewCellStyleValue2
6.UITableViewCell設(shè)置右邊輔助視圖accessoryType;
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryCheckmark
7.快捷創(chuàng)建代碼方法中<#???#>用法璃搜。
8.中文字前面不要加\拖吼,會(huì)把\后面的中文轉(zhuǎn)義,正確描述:圖書/音像
UIAlertView?*alert?=?[[UIAlertView?alloc]?initWithTitle:@"產(chǎn)品信息展示"?message:@"哈哈哈哈哈"?delegate:nil?cancelButtonTitle:@"ABC"?otherButtonTitles:@"123",@"456",?nil];
//?彈出UIAlertView
[alert?show];
UIAlertView?*alert?=?[[UIAlertView?alloc]?initWithTitle:@"產(chǎn)品信息展示"?message:@"哈哈哈哈哈"?delegate:nil?cancelButtonTitle:@"取消"?otherButtonTitles:@"確定",?nil];
//?彈出UIAlertView
[alert?show];
UIAlertView?*alert?=?[[UIAlertView?alloc]?initWithTitle:@"產(chǎn)品信息展示"?message:p.name?delegate:nil?cancelButtonTitle:@"取消"?otherButtonTitles:@"確定",?nil];
alert.alertViewStyle?=?UIAlertViewStyleLoginAndPasswordInput;
//?彈出UIAlertView
[alert?show];
UIAlertView?*alert?=?[[UIAlertView?alloc]?initWithTitle:@"產(chǎn)品信息展示"?message:p.name?delegate:nil?cancelButtonTitle:@"取消"?otherButtonTitles:@"確定",?nil];
alert.alertViewStyle?=?UIAlertViewStylePlainTextInput;
//?彈出UIAlertView
[alert?show];
UIAlertView?*alert?=?[[UIAlertView?alloc]?initWithTitle:@"產(chǎn)品信息展示"?message:p.name?delegate:nil?cancelButtonTitle:@"取消"?otherButtonTitles:@"確定",?nil];
alert.alertViewStyle?=?UIAlertViewStyleSecureTextInput;
//?彈出UIAlertView
[alert?show];
步驟一:設(shè)置UIAlertView的代理
步驟二:遵守UIAlertView的協(xié)議
步驟三:實(shí)現(xiàn)UIAlertView的按鈕點(diǎn)擊協(xié)議方法这吻。
步驟一:?取出文本框文字
注意UIAlertView中的文本框的角標(biāo)是根據(jù)UIAlertView從上到下第幾個(gè)文本框決定的吊档。最上面的文本框角標(biāo)為0.
步驟二:修改模型數(shù)據(jù)
步驟三:刷新表格
12.UITableView中的reloadData,會(huì)重新整個(gè)表格。
//指定刷新indexPaths數(shù)組里的行數(shù)唾糯。
注意indexPaths里存儲(chǔ)的是NSIndexPath對(duì)象
UITableView默認(rèn)只會(huì)加載出現(xiàn)在屏幕上面的cell怠硼,沒當(dāng)有一個(gè)cell移除屏幕,就會(huì)存儲(chǔ)到緩存池里找移怯。
性能優(yōu)化步驟:
步驟一:定義cell的標(biāo)識(shí)(不需要每次都創(chuàng)建cell標(biāo)識(shí)香璃,因此需要使用static,static標(biāo)識(shí)只會(huì)在第一次創(chuàng)建,以后都不會(huì)創(chuàng)建了。)
步驟二:從緩存池里取cell
步驟三:判斷取出cell是否為空肌索,如果為空就手動(dòng)創(chuàng)建cell。