×

小心使用cell的contentView

96
fever105
2017.12.05 17:14 字数 693

小心使用cell的contentView

UITableViewCell是每个iOS开发者都必须掌握的。我们都知道,应当将子视图加入其contentView,而非cell本身。但为什么这样做,如果不这样做有什么后果,你知道吗?

最近在开发中遇到一个问题:使用contentView做insets效果时,Auto Layout产生冲突。

起因源于需要实现这种效果:

图1

即内容与cell四边保持距离,可以用UIEdgeInsets表示。根据以往经验,既然所有子视图都被加入contentView,那么使用它做insets再合适不过了。代码如下:

contentView.snp.makeConstraints { (make) in
    make.edges.equalToSuperview().inset(UIEdgeInsets(top: 10.0, left: 5.0, bottom: 10.0, right: 5.0))
}

但运行后的效果却不是我们想要的:

图2

查看console中出现错误信息,提示布局冲突(这里我使用self-sizing cell,即cell的高度由Auto Layout自动计算):

图3

仔细观察,可以发现:UIView-Encapsulated-Layout-Height这条约束与cell的总体高度(20.0 + label高度 + 20.0)冲突,系统选择打破底部约束。从字面意思来看,前者似乎也在定义cell高度。而且,经过Google,发现这条约束由系统设置,优先级为required,无法降级。

网上给出的说法是将我们自己的约束降级,避免冲突。但这种做法不符合需求:UIView-Encapsulated-Layout-Height这条约束所定义的cell高度不是我们想要的。那么,到底是哪里出了问题呢?

经过反复测试,终于发现问题所在:只要不使用contentView做insets,就一切安好。那么,为什么不能呢?带着强烈的好奇心,我翻阅文档。文档对于contentView的解释是这样的:

图4

要点如下:

  1. cell子视图必须加入contentView;
  2. 之所以必须加入contentView,是因为在编辑模式下,cell会操作contentView。如下图所示:
图6

此外,还在大片的错误信息中发现了一段非常不起眼提示:

图5

大意为:不要修改contentView属性translatesAutoresizingMaskIntoConstraints,否则后果自负😂。

SnapKit会自动修改视图的这个属性(false),怪不得会触发这个警告。

结论

经过上面的思考,可以得出结论:

  1. 子视图都必须加入contentView
  2. 不要修改contentView的布局属性,frame也好,添加约束也好,都是禁止的。

可能有人会问,这样的话如何实现insets效果呢?答案很简单:创建一个containerView,将所有子视图放到里面,然后把它加入contentView,再做insets。例如:

图7
iOS Dev
Web note ad 1