小心使用cell的contentView
UITableViewCell是每個(gè)iOS開(kāi)發(fā)者都必須掌握的固以。我們都知道治笨,應(yīng)當(dāng)將子視圖加入其contentView,而非cell本身。但為什么這樣做肉康,如果不這樣做有什么后果修己,你知道嗎?
最近在開(kāi)發(fā)中遇到一個(gè)問(wèn)題:使用contentView做insets效果時(shí)迎罗,Auto Layout產(chǎn)生沖突睬愤。
起因源于需要實(shí)現(xiàn)這種效果:
即內(nèi)容與cell四邊保持距離,可以用UIEdgeInsets
表示纹安。根據(jù)以往經(jīng)驗(yàn)尤辱,既然所有子視圖都被加入contentView,那么使用它做insets再合適不過(guò)了厢岂。代碼如下:
contentView.snp.makeConstraints { (make) in
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 10.0, left: 5.0, bottom: 10.0, right: 5.0))
}
但運(yùn)行后的效果卻不是我們想要的:
查看console中出現(xiàn)錯(cuò)誤信息光督,提示布局沖突(這里我使用self-sizing cell,即cell的高度由Auto Layout自動(dòng)計(jì)算):
仔細(xì)觀察塔粒,可以發(fā)現(xiàn):UIView-Encapsulated-Layout-Height
這條約束與cell的總體高度(20.0 + label高度 + 20.0)沖突结借,系統(tǒng)選擇打破底部約束。從字面意思來(lái)看卒茬,前者似乎也在定義cell高度船老。而且,經(jīng)過(guò)Google圃酵,發(fā)現(xiàn)這條約束由系統(tǒng)設(shè)置柳畔,優(yōu)先級(jí)為required
,無(wú)法降級(jí)郭赐。
網(wǎng)上給出的說(shuō)法是將我們自己的約束降級(jí)薪韩,避免沖突。但這種做法不符合需求:UIView-Encapsulated-Layout-Height這條約束所定義的cell高度不是我們想要的捌锭。那么俘陷,到底是哪里出了問(wèn)題呢?
經(jīng)過(guò)反復(fù)測(cè)試观谦,終于發(fā)現(xiàn)問(wèn)題所在:只要不使用contentView做insets拉盾,就一切安好。那么坎匿,為什么不能呢盾剩?帶著強(qiáng)烈的好奇心,我翻閱文檔替蔬。文檔對(duì)于contentView的解釋是這樣的:
要點(diǎn)如下:
- cell子視圖必須加入contentView告私;
- 之所以必須加入contentView,是因?yàn)樵诰庉嬆J较鲁星牛琧ell會(huì)操作contentView驻粟。如下圖所示:
此外,還在大片的錯(cuò)誤信息中發(fā)現(xiàn)了一段非常不起眼提示:
大意為:不要修改contentView屬性translatesAutoresizingMaskIntoConstraints
,否則后果自負(fù)??蜀撑。
SnapKit會(huì)自動(dòng)修改視圖的這個(gè)屬性(false)挤巡,怪不得會(huì)觸發(fā)這個(gè)警告。
結(jié)論
經(jīng)過(guò)上面的思考酷麦,可以得出結(jié)論:
- 子視圖都必須加入contentView
- 不要修改contentView的布局屬性矿卑,frame也好,添加約束也好沃饶,都是禁止的母廷。
可能有人會(huì)問(wèn),這樣的話如何實(shí)現(xiàn)insets效果呢糊肤?答案很簡(jiǎn)單:創(chuàng)建一個(gè)containerView琴昆,將所有子視圖放到里面,然后把它加入contentView馆揉,再做insets业舍。例如: