UITableView的數(shù)據(jù)源(dataSource)和代理(delegate)
UITableView需要一個(gè)數(shù)據(jù)源(dataSource)來顯示數(shù)據(jù),UITableView會向數(shù)據(jù)源查詢一共有多少行數(shù)據(jù)以及每一行顯示什么數(shù)據(jù)等。沒有設(shè)置數(shù)據(jù)源的UITableView只是個(gè)空殼。凡是遵守UITableViewDataSource協(xié)議的OC對象,都可以是UITableView的數(shù)據(jù)源。
通常都要為UITableView設(shè)置代理對象(delegate),以便在UITableView觸發(fā)一下事件時(shí)做出相應(yīng)的處理,比如選中了某一行。凡是遵守了UITableViewDelegate協(xié)議的OC對象,都可以是UITableView的代理對象。一般會讓控制器充當(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對象(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;
某一行是否可以移動來進(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ìn)(數(shù)字越小,等級越高)
UITableViewCell
UITableView的每一行都是一個(gè)UITableViewCell,通過dataSource的
tableView:cellForRowAtIndexPath:方法來初始化每一行
UITableViewCell是UIView的子類,內(nèi)部有個(gè)默認(rèn)的子視圖:contentView。contentView是UITableViewCell所顯示內(nèi)容的父視圖,并負(fù)責(zé)顯示一些輔助指示視圖。輔助指示視圖的作用是顯示一個(gè)表示動作的圖標(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對象的重用原理
iOS設(shè)備的內(nèi)存有限,如果用UITableView顯示成千上萬條數(shù)據(jù),就需要成千上萬個(gè)UITableViewCell對象的話,那將會耗盡iOS設(shè)備的內(nèi)存。要解決該問題,需要重用UITableViewCell對象
重用原理:當(dāng)滾動列表時(shí),部分UITableViewCell會移出窗口,UITableView會將窗口外的UITableViewCell放入一個(gè)對象池中,等待重用。當(dāng)UITableView要求dataSource返回UITableViewCell時(shí),dataSource會先查看這個(gè)對象池,如果池中有未使用的UITableViewCell,dataSource會用新的數(shù)據(jù)配置這個(gè)UITableViewCell,然后返回給UITableView,重新顯示到窗口中,從而避免創(chuàng)建新對象
還有一個(gè)非常重要的問題:有時(shí)候需要自定義UITableViewCell(用一個(gè)子類繼承UITableViewCell),而且每一行用的不一定是同一種UITableViewCell(如短信聊天布局),所以一個(gè)UITableView可能擁有不同類型的UITableViewCell,對象池中也會有很多不同類型的UITableViewCell,那么UITableView在重用UITableViewCell時(shí)可能會得到錯(cuò)誤類型的UITableViewCell
解決方案:UITableViewCell有個(gè)NSString?*reuseIdentifier屬性,可以在初始化UITableViewCell的時(shí)候傳入一個(gè)特定的字符串標(biāo)識來設(shè)置reuseIdentifier(一般用UITableViewCell的類名)。當(dāng)UITableView要求dataSource返回UITableViewCell時(shí),先通過一個(gè)字符串標(biāo)識到對象池中查找對應(yīng)類型的UITableViewCell對象,如果有,就重用,如果沒有,就傳入這個(gè)字符串標(biāo)識來初始化一個(gè)UITableViewCell對象
重用UITableViewCell對象
-?(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中的某一行(帶動畫效果)
[tableView?deleteRowsAtIndexPaths:[NSArray?arrayWithObject:indexPath]?withRowAnimation:UITableViewRowAnimationLeft];
//如果不考慮動畫效果,也可以直接[tableView?reload];
}
}
移動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í)會調(diào)用此方法(UITableViewDelegate的方法)
-?(void)tableView:(UITableView?*)tableView?didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
//取消選中某一行,讓被選中行的高亮顏色消失(帶動畫效果)
[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找到對應(yīng)的UITableViewCell對象
-?(void)setEditing:(BOOL)editing?animated:(BOOL)animated
是否要開啟編輯模式
-?(void)deselectRowAtIndexPath:(NSIndexPath?*)indexPath?animated:(BOOL)animated
取消選中某一行,讓被選中行的高亮顏色消失(帶動畫效果)
-?(id)dequeueReusableCellWithIdentifier:(NSString?*)identifier
通過identifier在(緩存)池中找到對應(yīng)的UITableViewCell對象
-?(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è)對象。UITableViewController對象被創(chuàng)建后,會將這個(gè)UITableView對象的dataSource和delegate指向UITableViewController自己
一、UITableView
1.數(shù)據(jù)展示的條件
1>?UITableView的所有數(shù)據(jù)都是由數(shù)據(jù)源(dataSource)提供的,所以要想在UITableView展示數(shù)據(jù),必須設(shè)置UITableView的dataSource數(shù)據(jù)源對象
2>要想當(dāng)UITableView的dataSource對象,必須遵守UITableViewDataSource協(xié)議,實(shí)現(xiàn)相應(yīng)的數(shù)據(jù)源方法
3>當(dāng)UITableView想要展示數(shù)據(jù)的時(shí)候,就會給數(shù)據(jù)源發(fā)送消息(調(diào)用數(shù)據(jù)源方法),UITableView會根據(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整體刷新(每一行都會刷新)
*?-?(void)reloadRowsAtIndexPaths:(NSArray?*)indexPathswithRowAnimation:(UITableViewRowAnimation)animation
局部刷新
5.性能優(yōu)化
1>定義一個(gè)循環(huán)利用標(biāo)識
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ù)源方法,此方法會自動調(diào)用。
返回有多少組
返回一組有多少行
返回每一行顯示的UITableViewCell(繼承UIView),initWithStyle使用這個(gè)方法調(diào)用。
注意UITableView的數(shù)據(jù)源的方法普遍都是以tableView開頭。
步驟四:用數(shù)組管理數(shù)據(jù)。
步驟五:每個(gè)數(shù)組中都是一個(gè)字典,key:(header,footer,cityes).
4.創(chuàng)建模型的時(shí)候,自定義一個(gè)工廠方法(類方法)接口給外界調(diào)用。
工廠方法好處:簡化對象的實(shí)例化,快速創(chuàng)建對象。
UITableViewCellStyleDefault
UITableViewCellStyleValue1
UITableViewCellStyleSubtitle
UITableViewCellStyleValue2
6.UITableViewCell設(shè)置右邊輔助視圖accessoryType;
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryCheckmark
8.中文字前面不要加\,會把\后面的中文轉(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,會重新整個(gè)表格。
//指定刷新indexPaths數(shù)組里的行數(shù)。
注意indexPaths里存儲的是NSIndexPath對象
UITableView默認(rèn)只會加載出現(xiàn)在屏幕上面的cell,沒當(dāng)有一個(gè)cell移除屏幕,就會存儲到緩存池里找。
性能優(yōu)化步驟:
步驟一:定義cell的標(biāo)識(不需要每次都創(chuàng)建cell標(biāo)識,因此需要使用static,static標(biāo)識只會在第一次創(chuàng)建,以后都不會創(chuàng)建了。)
步驟二:從緩存池里取cell
步驟三:判斷取出cell是否為空,如果為空就手動創(chuàng)建cell。