1.基本介紹:
UITableView 有兩種風(fēng)格:UITableViewStylePlain不分組樣式和UITableViewStyleGrouped分組樣式。 UITableViewStylePlain 和 UITableViewStyleGrouped 這兩者操作起來其實并沒有本質(zhì)區(qū)別,只是后者按分組樣式顯示前者按照普通樣式顯示而已。
在UITableView中數(shù)據(jù)只有行的概念,并沒有列的概念。UITableView中每行數(shù)據(jù)都是一個UITableViewCell
在這個控件中為了顯示更多的信息,iOS已經(jīng)在其內(nèi)部設(shè)置好了多個子控件以供開發(fā)者使用。如果我們查看UITableViewCell的聲明文件可以發(fā)現(xiàn)在內(nèi)部有一個UIView控件(contentView,作為其他元素的父控件)、兩個UILable控件(textLabel、detailTextLabel)、一個UIImage控件(imageView),分別用于容器、顯示內(nèi)容、詳情和圖片。使用效果類似于微信、QQ信息列表。
這些子控件并不一定要全部使用,具體操作時可以通過UITableViewCellStyle進(jìn)行設(shè)置:
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault, // 左側(cè)顯示textLabel(不顯示detailTextLabel),imageView可選(顯示在最左邊)
UITableViewCellStyleValue1, // 左側(cè)顯示textLabel、右側(cè)顯示detailTextLabel(默認(rèn)藍(lán)色),imageView可選(顯示在最左邊)
UITableViewCellStyleValue2, // 左側(cè)依次顯示textLabel(默認(rèn)藍(lán)色)和detailTextLabel,imageView可選(顯示在最左邊)
UITableViewCellStyleSubtitle // 左上方顯示textLabel,左下方顯示detailTextLabel(默認(rèn)灰色),imageView可選(顯示在最左邊)
};
2.數(shù)據(jù)源 -- dataSource
由于iOS是遵循MVC模式設(shè)計的,很多操作都是通過代理和外界溝通的,但對于數(shù)據(jù)源控件除了代理還有一個數(shù)據(jù)源屬性,通過它和外界進(jìn)行數(shù)據(jù)交互。 對于UITableView設(shè)置完dataSource后需要實現(xiàn)UITableViewDataSource協(xié)議,在這個協(xié)議中定義了多種數(shù)據(jù)操作方法。
UITableView需要一個數(shù)據(jù)源(dataSource)來顯示數(shù)據(jù),UITableView會向數(shù)據(jù)源查詢一共有多少行數(shù)據(jù)以及每一行顯示什么數(shù)據(jù)等。沒有設(shè)置數(shù)據(jù)源的UITableView只是個空殼。凡是遵守 UITableViewDataSource 協(xié)議的OC對象,都可以是UITableView的數(shù)據(jù)源。
通常都要為UITableView設(shè)置代理對象(delegate),以便在UITableView觸發(fā)一下事件時做出相應(yīng)的處理,比如選中了某一行。凡是遵守了UITableViewDelegate協(xié)議的OC對象,都可以是UITableView的代理對象。
一般會讓控制器充當(dāng)UITableView的dataSource和delegate,這就涉及到MVC的具體使用,如果 UITableView是在 自定義UIView中添加,則delegate和dataSource可以放置在 自定義UIVie的控制器中來進(jìn)行,相應(yīng)的數(shù)據(jù)源控制和方法觸發(fā)
3.方法的使用及描述
UITableViewDataSource/UITableViewDelegate
下面是涉及到的代理和數(shù)據(jù)源的所有正常使用提供的方法
@required
//第section分區(qū)一共有多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
//創(chuàng)建第section分區(qū)第row行的cell對象(indexPath包含了section和row),加載cell對象數(shù)據(jù)。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
@end
@optional
//一共有多少個分區(qū)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
//第section分區(qū)的頭部標(biāo)題
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
//第section分區(qū)的底部標(biāo)題
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
//某一行是否可以編輯(刪除)
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
//某一行是否可以移動來進(jìn)行重新排序
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
//UITableView右邊的索引欄的內(nèi)容
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
//選中了UITableView的某一行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
//某一行的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
//第section分區(qū)頭部的高度
- (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;
//設(shè)置每一行的等級縮進(jìn)(數(shù)字越小,等級越高)
- (NSInteger)tableView:(UITableView *)tableViewindentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath;
@end
4.UITableViewCell對象的重用原理
重用原理:當(dāng)滾動列表時,部分UITableViewCell會移出窗口,UITableView會將窗口外的UITableViewCell放入一個對象池中,等待重用。當(dāng)UITableView要求dataSource返回UITableViewCell時,dataSource會先查看這個對象池,如果池中有未使用的UITableViewCell,dataSource會用新的數(shù)據(jù)配置這個UITableViewCell,然后返回給UITableView,重新顯示到窗口中,從而避免創(chuàng)建新對象
一個非常重要的問題:有時候需要自定義UITableViewCell(用一個子類繼承UITableViewCell),而且每一行用的不一定是同一種UITableViewCell(如短信聊天布局),所以一個UITableView可能擁有不同類型的UITableViewCell,對象池中也會有很多不同類型的UITableViewCell,那么UITableView在重用UITableViewCell時可能會得到錯誤類型的UITableViewCell
解決方案:UITableViewCell有個NSString *reuseIdentifier屬性,可以在初始化UITableViewCell的時候傳入一個特定的字符串標(biāo)識來設(shè)置reuseIdentifier(一般用UITableViewCell的類名)。當(dāng)UITableView要求dataSource返回UITableViewCell時,先通過一個字符串標(biāo)識到對象池中查找對應(yīng)類型的UITableViewCell對象,如果有,就重用,如果沒有,就傳入這個字符串標(biāo)識來初始化一個UITableViewCell對象
重用UITableViewCell對象: -- 使用方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 配置一個cell 的重用ID
static NSString *id = @"UITableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"id"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"id"];
}
cell.textLabel.text = [NSString stringWithFormat:@"Text %li", indexPath.row];
return cell;
}
5.UITableViewCell的常用屬性:
設(shè)置背景:backgroundView -- 設(shè)置被選中時的背景視圖:selectedBackgroundView
selectionStyle屬性可設(shè)置UITableViewCell被選中時的背景顏色:
- UITableViewCellSelectionStyleNone沒有顏色
- UITableViewCellSelectionStyleBlue藍(lán)色(默認(rèn))
- UITableViewCellSelectionStyleGray灰色
6.自定義UITableViewCell
> 1. 新建一個繼承自:UITableViewCell類
> 2. 重寫:initWithStyle:reuseIdentifier:方法
-->添加所有需要顯示的子控件(而不需要設(shè)置子控件的數(shù)據(jù)和frame,子控件要添加到contentView中)
-->進(jìn)行子控件的一次性設(shè)置(有些屬性只需要設(shè)置一次,如字體、圖片等)
> 3.提供2個模型
-->數(shù)據(jù)模型:存放文字?jǐn)?shù)據(jù)/圖片數(shù)據(jù)
-->frame模型:存放數(shù)據(jù)模型/所有子控件的frame/cell高度
4.cell擁有一個frame模型,不要直接擁有數(shù)據(jù)模型。
5.重寫frame模型的屬性的setter方法:在這個方法中設(shè)置顯示數(shù)據(jù)和frame
6.frame模型數(shù)據(jù)的初始化已經(jīng)采取懶加載的方式(每個cell對應(yīng)的frame模型數(shù)據(jù)只加載一次)。
7.UITableView使用方法步驟
>1>一共有多少組;- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
>2>第section組一共有多少行:@required - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
>3>第indexPath.section組 第indexPath.row行顯示怎樣的cell(顯示什么內(nèi)容,加載數(shù)據(jù))@required:- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath。 在這個方法中使用:tableCell.textLabel.text=[[NSArray array] objectAtIndex:indexPath.row]; 可以在UITableViewCell中依次顯示數(shù)組中的內(nèi)容
>4>第section組顯示怎樣的頭部標(biāo)題:-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
>5>第section組顯示怎樣的尾部標(biāo)題:- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
>6>選中某一行操作:-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
8.tableView刷新數(shù)據(jù)的方式
1). 修改模型數(shù)據(jù)
2). 全局刷新:[self.tableView reloadData];
3). 修改局部刷新:前提是模型數(shù)據(jù)的個數(shù)不變,所以可以進(jìn)行局部刷新:[self.tableView reloadRowsAtIndexPaths:@[indexPath]withRowAnimation:UITableViewRowAnimationBottom];
4). 刪除局部刷新:[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0inSection:0]] withRowAnimation:UITableViewRowAnimationMiddle];
9.添加每個cell出現(xiàn)時的3D動畫
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
// 動畫1
// CATransform3D rotation;//3D旋轉(zhuǎn)
// rotation = CATransform3DMakeRotation( (90.0*M_PI)/180, 0.0, 0.7, 0.4);
// //逆時針旋轉(zhuǎn)
// rotation.m34 = 1.0/ -600;
//
// cell.layer.shadowColor = [[UIColor blackColor]CGColor];
// cell.layer.shadowOffset = CGSizeMake(10, 10);
// cell.alpha = 0;
//
// cell.layer.transform = rotation;
//
// [UIView beginAnimations:@"rotation" context:NULL];
// //旋轉(zhuǎn)時間
// [UIView setAnimationDuration:0.8];
// cell.layer.transform = CATransform3DIdentity;
// cell.alpha = 1;
// cell.layer.shadowOffset = CGSizeMake(0, 0);
// [UIView commitAnimations];
// 動畫2
cell.alpha = 0.5;
CGAffineTransform transformScale = CGAffineTransformMakeScale(0.3,0.8);
CGAffineTransform transformTranslate = CGAffineTransformMakeTranslation(0.5, 0.6);
cell.transform = CGAffineTransformConcat(transformScale, transformTranslate);
[tableView bringSubviewToFront:cell];
[UIView animateWithDuration:.4f
delay:
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
cell.alpha = ;
//清空 transform
cell.transform = CGAffineTransformIdentity;
} completion:nil];
// 動畫3
/*
// 從錨點位置出發(fā),逆時針繞 Y 和 Z 坐標(biāo)軸旋轉(zhuǎn)90度
CATransform3D transform3D = CATransform3DMakeRotation(M_PI_2, 0.0, 1.0, 1.0);
// 定義 cell 的初始狀態(tài)
cell.alpha = 0.0;
cell.layer.transform = transform3D;
cell.layer.anchorPoint = CGPointMake(0.0, 0.5); // 設(shè)置錨點位置;默認(rèn)為中心點(0.5, 0.5)
// 定義 cell 的最終狀態(tài),執(zhí)行動畫效果
// 方式一:普通操作設(shè)置動畫
[UIView beginAnimations:@"transform" context:NULL];
[UIView setAnimationDuration:0.5];
cell.alpha = 1.0;
cell.layer.transform = CATransform3DIdentity;
CGRect rect = cell.frame;
rect.origin.x = 0.0;
cell.frame = rect;
[UIView commitAnimations];
// 方式二:代碼塊設(shè)置動畫
// [UIView animateWithDuration:0.5 animations:^{
// cell.alpha = 1.0;
// cell.layer.transform = CATransform3DIdentity;
// CGRect rect = cell.frame;
// rect.origin.x = 0.0;
// cell.frame = rect;
// }];
*/
}
>> UITableViewCell可移動,需要打開的代理方法以及移動過程中調(diào)用的代理方法
// tableView可移動 移動完成之后會調(diào)用此代理方法
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
}
// 移動過程中調(diào)用的代理方法 -- 示例為不能跨區(qū)移動
/**
* <#Description#>
*
* @param tableView
* @param sourceIndexPath 所要移動單元格的原始位置
* @param proposedDestinationIndexPath 將要移動到的位置
*
* @return return value description
*/
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
// 移動位置在同一分區(qū)
if (sourceIndexPath.section == proposedDestinationIndexPath.section)
{
// 這時允許單元格移動
return proposedDestinationIndexPath ;
}
// 不在同一分區(qū) 不讓單元格移動,返回原始的indexPath
else
{
return sourceIndexPath ;
}
}