iOS回顧筆記(08) -- 自定義Cell的類型和創建步驟總結
項目中我們常見的自定義cell主要分為兩種
-
等高cell:
如應用列表、功能列表
-
非等高cell:
如微博列表、QQ聊天頁面

下面對這兩類cell的創建方式簡單記錄各步驟。
等高Cell
等高cell通常有三種創建方式:
- storyboard自定義cell
- xib自定義cell
- 代碼創建cell(使用frame計算/使用Autolayout布局)
下面分別記錄每種創建步驟:
1. storyboard自定義cell
-
1.創建一個繼承自UITableViewCell的子類,比如XYDealCell
-
2.在storyboard中
-
往cell里面增加需要用到的子控件
-
設置cell的重用標識
-
設置cell的class為XYDealCell

-
-
3.在控制器中
- 利用重用標識找到cell
- 給cell傳遞模型數據
-
4.在XYDealCell中
- 將storyboard中的子控件連線到類擴展中

- 需要提供一個模型屬性,重寫模型的set方法,在這個方法中設置模型數據到子控件上
- 將storyboard中的子控件連線到類擴展中
2.xib自定義cell
- 1.創建一個繼承自UITableViewCell的子類,比如XYDealCell
- 2.創建一個xib文件(文件名建議跟cell的類名一樣),比如XYDealCell.xib
- 拖拽一個UITableViewCell出來
- 修改cell的class為XYDealCell
- 設置cell的重用標識
- 往cell中添加需要用到的子控件
- 3.在控制器中
- 利用registerNib...方法注冊xib文件
- 利用重用標識找到cell(如果沒有注冊xib文件,就需要手動去加載xib文件)
- 給cell傳遞模型數據
- 4.在XYDealCell中
- 將xib中的子控件連線到類擴展中
- 需要提供一個模型屬性,重寫模型的set方法,在這個方法中設置模型數據到子控件上
- 也可以將創建獲得cell的代碼封裝起來(比如cellWithTableView:方法)
3.代碼自定義cell(使用frame)
- 1.創建一個繼承自UITableViewCell的子類,比如XYDealCell
- 在initWithStyle:reuseIdentifier:方法中
- 添加子控件
- 設置子控件的初始化屬性(比如文字顏色、字體)
- 在layoutSubviews方法中設置子控件的frame
- 需要提供一個模型屬性,重寫模型的set方法,在這個方法中設置模型數據到子控件
- 在initWithStyle:reuseIdentifier:方法中
- 2.在控制器中
- 利用registerClass...方法注冊XYDealCell類
- 利用重用標識找到cell(如果沒有注冊類,就需要手動創建cell)
- 給cell傳遞模型數據
- 也可以將創建獲得cell的代碼封裝起來(比如cellWithTableView:方法)
4.代碼自定義cell(使用autolayout)
- 1.創建一個繼承自UITableViewCell的子類,比如XYDealCell
- 在initWithStyle:reuseIdentifier:方法中
- 添加子控件
- 添加子控件的約束(建議使用
Masonry
) - 設置子控件的初始化屬性(比如文字顏色、字體)
- 需要提供一個模型屬性,重寫模型的set方法,在這個方法中設置模型數據到子控件
- 在initWithStyle:reuseIdentifier:方法中
- 2.在控制器中
- 利用registerClass...方法注冊XYDealCell類
- 利用重用標識找到cell(如果沒有注冊類,就需要手動創建cell)
- 給cell傳遞模型數據
- 也可以將創建獲得cell的代碼封裝起來(比如cellWithTableView:方法)
非等高cell
- xib自定義cell(重點)
- 在模型中增加一個cellHeight屬性,用來存放對應cell的高度
- 在cell的模型屬性set方法中調用[self layoutIfNeed]方法強制布局,然后計算出模型的cellheight屬性值
- 在控制器中實現tableView:estimatedHeightForRowAtIndexPath:方法,返回一個估計高度,比如200
- 在控制器中實現tableView:heightForRowAtIndexPath:方法,返回cell的真實高度(模型中的cellHeight屬性)
- storyboard自定義cell
- 代碼自定義cell(frame)
- 代碼自定義cell(Autolayout)
非等高Cell的幾個小重點知識
1. tableview返回行高的方法
/**
* 精確返回每行cell的高度,此方法會真實計算對應高度值,並會一次性算出所有行高
*/
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100;
}
/**
* 估測返回每行cell的高度,添加此方法可以修改調用順序,不進行一次性精確計算,先返回cell,在根據每行的展示計算對應真實高度,用到哪個算哪個,提高性能
*/
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
return 200;
}
如果直接調用計算行高方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
程序的調用順序是
- 調用
heightForRowAtIndexPath
返回所有行高 - 調用
cellForRowAtIndexPath
返回對應行
如果先調用估算高度方法
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath;
程序的調用順序是
- 調用
estimatedHeightForRowAtIndexPath
返回所有行高 - 調用
cellForRowAtIndexPath
返回對應行 - 調用
cellForRowAtIndexPath
返回對應的真實行高
所以使用估算行高的方法可提高效率。
【注意】
經過iOS 11適配的測試發現:add time:2017年12月07日17:56:03
iOS 11 中tableViewCell的高度計算順序發生變化
iOS 11 中數據源方法的調用順序(無論有沒有估算高度都是直接先執行cellForRow)
estimatedHeightForRow --> cellForRow -- > heightForRow 或
cellForRow -- > heightForRow
iOS 10 以下有沒有估算高度是不同的
estimatedHeightForRow --> cellForRow -- > heightForRow
heightForRow -- > cellForRow
2. 強制布局方法 : [cell layoutIfNeeded];
-
當cell調用setModel方法后,雖已賦值,但cell尚未展示。所以系統不會根據約束進行布局。所以此時無法得到cell真實的frame等數值。
-
[cell layoutIfNeeded]就是在給cell賦值之后調用,強制進行布局,可得到cell真實的frame值
3. UILabel限制最大高度 : preferredMaxLayoutWidth
- UILabel在自動布局時比較特殊。系統會自動根據內容計算它的寬高,所以只需設置位置約束就行系統自動計算UILabel的寬高時,會默認完全包裹其內部的文字內容:
- 為防止系統自動計算Label高度時候,按照完全包裹內容,所以需要在Label創建完之后明確設置Label的自動布局最大寬度,如下方法:
- (void)awakeFromNib
{
// 設置自己的昵稱Label的最大自動布局的寬度為 cell 的寬度減去 20
self.nameLabel.preferredMaxLayoutWidth = self.bounds.size.width - 20;
}
小結
- 項目中cell類型常見有兩種:等高cell 和 非等高cell
- 等高cell自定義,由於不用關心高度計算問題、推薦使用Xib、StoryBoard。
- 非等高cell自定義,推薦使用Xib。