UITableView的樣式
UITableView是iOS開發(fā)中非常重要的控件之一,它能夠展示多行數(shù)據(jù),支持滾動(dòng).在大部分APP中都占有很大的比重.
- UITableView的創(chuàng)建方式:
- storyboard:直接拖到控制器中即可.
- 代碼
//代碼創(chuàng)建
UITableView *tableView = [[UITableView alloc] init];
//設(shè)置frame
tableView.frame = self.view.bounds;
[self.view addSubview:tableView];
- UITableView有兩種樣式:plain和grouped.如圖所示,
圖1是plain樣式即所有的cell都在黏在一起,沒有明顯的區(qū)分.圖2是grouped樣式,是分組的.


可以看到兩種格式的區(qū)別非常明顯.
在UITableView中,每一個(gè)單元格被稱為cell,如果想在UITableView中顯示數(shù)據(jù),需要設(shè)置UITableView中cell的數(shù)量及每個(gè)cell顯示的內(nèi)容.UITableView并不能直接顯示數(shù)據(jù),它需要設(shè)置數(shù)據(jù)源(datasource),數(shù)據(jù)源遵守<UITableViewDataSource>協(xié)議,并實(shí)現(xiàn)其中對(duì)應(yīng)的方法設(shè)置數(shù)據(jù)及內(nèi)容即可.
<UITableViewDataSource>中常用的方法:
@required(必須實(shí)現(xiàn)的)
//返回第section行的row數(shù)量
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
//返回第indexPath.row行的cell內(nèi)容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
以上這兩個(gè)方法會(huì)調(diào)用一次或多次,次數(shù)根據(jù)設(shè)置的section數(shù)量及每個(gè)section的cell數(shù)量而定.在開發(fā)中一般通過模型來(lái)傳遞數(shù)據(jù),在控制器中創(chuàng)建一個(gè)數(shù)組接收模型數(shù)據(jù),然后加載到cell中顯示.
@optional(可選的)
//返回section的數(shù)量,默認(rèn)為1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
//返回grouped樣式中每組的頭部標(biāo)題
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
//返回grouped樣式中每組的尾部標(biāo)題
- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
UITableViewCell的創(chuàng)建及重用
UITableViewCell在創(chuàng)建時(shí),系統(tǒng)會(huì)自動(dòng)設(shè)置為懶加載狀態(tài).但為了高效利用每一個(gè)cell,我們需要設(shè)置cell的重用標(biāo)識(shí)(identfier),加載cell時(shí)先從緩存池中查找可用的cell.
UITableViewCell的創(chuàng)建方式1:純代碼
- 設(shè)置如下:
//設(shè)置indexPath.row行的cell內(nèi)容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//設(shè)置重用標(biāo)識(shí)
static NSString *ID=@"cell";
//根據(jù)重用標(biāo)識(shí)從緩存池中查找可用cell
UITableViewCell *cell=[self.tableView dequeueReusableCellWithIdentifier:ID];
//找不到可用cell,手動(dòng)創(chuàng)建標(biāo)識(shí)為ID的cell
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
//板式輸出
cell.textLabel.text = [NSString stringWithFormat:@"test--%zd",indexPath.row];
//返回cell
return cell;
}
UITableViewCell的創(chuàng)建方式2:storyboard
- 設(shè)置如下:

在代碼中實(shí)現(xiàn)以下方法:
//設(shè)置indexPath.row行的cell內(nèi)容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//設(shè)置重用標(biāo)識(shí)
static NSString *ID=@"cell";
//根據(jù)重用標(biāo)識(shí)從緩存池中查找可用cell,如果找不到,系統(tǒng)會(huì)根據(jù)storyboard中的cell標(biāo)識(shí)創(chuàng)建cell.
UITableViewCell *cell=[self.tableView dequeueReusableCellWithIdentifier:ID];
//板式輸出
cell.textLabel.text = [NSString stringWithFormat:@"test--%zd",indexPath.row];
//返回cell
return cell;
}
UITableViewCell的創(chuàng)建方式3:register
實(shí)現(xiàn)方法如下:
//先在控制器中對(duì)cell的標(biāo)識(shí)注冊(cè)
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//設(shè)置重用標(biāo)識(shí)
static NSString *ID=@"cell";
//根據(jù)重用標(biāo)識(shí)從緩存池中查找可用cell,如果找不到,系統(tǒng)會(huì)根據(jù)注冊(cè)的cell標(biāo)識(shí)創(chuàng)建cell.
UITableViewCell *cell=[self.tableView dequeueReusableCellWithIdentifier:ID];
//板式輸出
cell.textLabel.text = [NSString stringWithFormat:@"test--%zd",indexPath.row];
//返回cell
return cell;
}
UITableView及UITableViewCell的一些屬性
UITableView繼承自UIScrollView,如果成為了UITableView的代理,也就意味著同樣遵守了UIScrollView的代理協(xié)議,可以實(shí)現(xiàn)UIScrollViewDelegate中的方法來(lái)監(jiān)聽UITableView的滾動(dòng)事件.
在UITableView中每個(gè)section的頭部或底部,如果想設(shè)置圖片,可以實(shí)現(xiàn)以下方法.
//在section的底部區(qū)域顯示一個(gè)UIView控件
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
return expression;
}
//在section的頭部區(qū)域顯示一個(gè)UIView控件
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
return expression;
}
如果想監(jiān)聽點(diǎn)擊某一行,可以實(shí)現(xiàn)以下方法:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
如果想設(shè)置tableView不顯示分割線,可以設(shè)置以下屬性
self.tableView separatorStyle = UITableViewCellSeparatorStyleNone;
UITableViewCell中的控件其實(shí)都添加到了cell中的Content View上面,在自定義控件添加時(shí),需要調(diào)用
[cell.contentView addSubview:(nonnull UIView *)]方法,添加到cell的.contentView中去,這也是蘋果官方推薦添加的一種方式.
創(chuàng)建自定義等高cell方式1:storyboard
- 在storyboard中放入一個(gè)UITableViewController(或者UIViewController中嵌套一個(gè)UITableView),系統(tǒng)會(huì)默認(rèn)自帶一個(gè)cell.

2.更改cell的重用標(biāo)識(shí)(identfier)

3.給每個(gè)cell綁定一個(gè)tag,方便設(shè)置數(shù)據(jù).

4.在數(shù)據(jù)源方法中設(shè)置cell的顯示內(nèi)容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID=@"cell";
UITableViewCell *cell=[self.tableView dequeueReusableCellWithIdentifier:ID];
//獲取模型數(shù)據(jù)
DLShop *shop = self.shops[indexPath.row];
//給cell賦值
UIImageView *iconView = (UIImageView *)[cell viewWithTag:1];
iconView.image = [UIImage imageNamed:shop.icon];
UILabel *titleLabel = (UILabel *)[cell viewWithTag:2];
titleLabel.text = shop.title;
UILabel *priceLabel = (UILabel *)[cell viewWithTag:3];
priceLabel.text = shop.price;
UILabel *buyCount = (UILabel *)[cell viewWithTag:4];
buyCount.text = shop.buyCount;
return cell;
}
storyboard中自定義cell需要用到tag,開發(fā)中會(huì)比較不方便,不推薦這種自定義方法.
創(chuàng)建自定義等高cell方式2:自定義cell
1.新建一個(gè)類

2.在storyboard中選中cell,修改class為類名

3.將cell中的控件拖線至新建類中

4.在新建類.h文件中包含模型類,定義一個(gè)模型屬性接收模型數(shù)據(jù)
#import <UIKit/UIKit.h>
@class DLShop;
@interface DLShopCell : UITableViewCell
// 定義模型屬性,接收數(shù)據(jù)
@property(nonatomic,strong) DLShop *shop;
@end
5.在新建類.m文件中,導(dǎo)入模型頭文件,重寫模型屬性的set方法,設(shè)置傳入的模型數(shù)據(jù)到子控件>
@implementation DLShopCell
-(void)setShop:(DLShop *)shop{
_shop = shop;
self.icon.image = [UIImage imageNamed:shop.icon];
self.title.text = shop.title;
self.price.text = [NSString stringWithFormat:@"¥%@",shop.price];
self.buyCount.text = [NSString stringWithFormat:@"%@人已購(gòu)買",shop.buyCount];
}
@end
6.在控制器中實(shí)現(xiàn)數(shù)據(jù)源方法,設(shè)置數(shù)據(jù)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID=@"cell";
// 新建一個(gè)DLShopCell類型的cell,保證創(chuàng)建的cell是我們自定義的
DLShopCell *cell=[self.tableView dequeueReusableCellWithIdentifier:ID];
//獲取模型數(shù)據(jù)
cell.shop = self.shops[indexPath.row];
return cell;
}
自定義類名創(chuàng)建cell比較方便,能很好的封裝cell控件,設(shè)置數(shù)據(jù)也很方便.
創(chuàng)建自定義等高cell方式3:xib自定義cell
1.新建一個(gè)xib文件,名稱與自定義類名保持一致.

2.修改xib的class為自定義類的名稱,保證創(chuàng)建時(shí)能夠找到xib文件

3.設(shè)置xib內(nèi)部cell的重用標(biāo)識(shí)

4.從xib拖線至自定義類中

5.在自定義類.h文件中包含模型類,定義一個(gè)模型屬性接收模型數(shù)據(jù),同時(shí)提供一個(gè)類方法,將tableView傳進(jìn)去.
#import <UIKit/UIKit.h>
@class DLShop;
@interface DLShopCell : UITableViewCell
// 定義模型屬性,接收數(shù)據(jù)
@property(nonatomic,strong) DLShop *shop;
// 外界傳入tableView,返回DLShopCell類型的cell
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@end
6.在.m文件中實(shí)現(xiàn)以上方法.
@implementation DLShopCell
//重寫模型屬性set方法設(shè)置傳入模型數(shù)據(jù)到子控件
-(void)setShop:(DLShop *)shop{
_shop = shop;
self.icon.image = [UIImage imageNamed:shop.icon];
self.title.text = shop.title;
self.price.text = [NSString stringWithFormat:@"¥%@",shop.price];
self.buyCount.text = [NSString stringWithFormat:@"%@人已購(gòu)買",shop.buyCount];
}
//實(shí)現(xiàn)cellWithTableView:將外界傳入tableView查找緩存池?cái)?shù)據(jù),如果沒有,創(chuàng)建并返回DLShopCell類型的cell
+ (instancetype)cellWithTableView:(UITableView *)tableView{
static NSString *ID = @"cell";
DLShopCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([DLShopCell class]) owner:nil options:nil] lastObject];
}
return cell;
}
@end
xib自定義cell完美實(shí)現(xiàn)了控件的封裝,將控件的所有屬性都包裝在自己內(nèi)部,推薦使用xib自定義cell,方便后期維護(hù)及使用.
懶加載
在控制器中新建數(shù)組屬性保存模型數(shù)據(jù)時(shí),一般會(huì)采用懶加載思想.步驟如下:
1.在控制器文件中定義一個(gè)數(shù)組,保存?zhèn)魅氲哪P蛿?shù)據(jù).
@interface TestTableViewController ()
// 用來(lái)保存?zhèn)魅氲哪P蛿?shù)據(jù)
@property(nonatomic,strong) NSArray *shops;
@end
2.重寫屬性的get方法,用到時(shí)再調(diào)用該屬性,以實(shí)現(xiàn)懶加載.
- (NSArray *)shops{
if (_shops == nil) {
NSString *path = [[NSBundle mainBundle] pathForResource:@"shops.plist" ofType:nil];
//取出字典數(shù)據(jù)轉(zhuǎn)為數(shù)組
NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
//創(chuàng)建一個(gè)空的可變數(shù)組接收模型數(shù)據(jù)
NSMutableArray *dealArrM = [NSMutableArray array];
//遍歷數(shù)組取出字典數(shù)據(jù)
for (NSDictionary *dict in dictArr) {
//定義模型接收字典數(shù)據(jù)
DLShop *shop = [DLShop shopWithDict:dict];
//將數(shù)據(jù)添加到模型
[dealArrM addObject:shop];
}//傳遞模型到成員變量中
_shops = dealArrM;
}
return _shops;
}
設(shè)置tableview有值時(shí)才顯示分割線
- (void)viewDidLoad{
[super ViewDidLoad];
//設(shè)置tableview有值時(shí)才顯示分割線
self.tableView.tableFooterView = [UIView alloc] init];
}