xyk blog

最近は iOS 開発の記事が多めです。

UITableViewCell の高さ変更時に制約エラー

検証環境:
Xcode 12
Swift 5.3
Deployment Target 11.0

UITableviewCell に vertical な UIStackView を配置して、セルタップ時にStackされているビューの isHidden プロパティを切り替えて、セルの高さを広げる処理をしたところ以下の制約エラーが発生した。

[LayoutConstraints] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x2835e1680 V:[UIStackView:0x13bf20060]-(>=0)-|   (active, names: '|':UITableViewCellContentView:0x13bf228b0 )>",
    "<NSLayoutConstraint:0x2835e1720 V:|-(0)-[UIStackView:0x13bf20060]   (active, names: '|':UITableViewCellContentView:0x13bf228b0 )>",
    "<NSLayoutConstraint:0x2835ecb90 'UISV-canvas-connection' UIStackView:0x13bf20060.top == UIStackView:0x13bf201f0.top   (active)>",
    "<NSLayoutConstraint:0x283685180 'UISV-canvas-connection' V:[UIStackView:0x13bf2c220]-(0)-|   (active, names: '|':UIStackView:0x13bf20060 )>",
    "<NSLayoutConstraint:0x2835dc3c0 'UISV-canvas-connection' UIStackView:0x13bf2c220.top == UIStackView:0x1261ea210.top   (active)>",
    "<NSLayoutConstraint:0x2835dc960 'UISV-canvas-connection' V:[UIStackView:0x1093d6f70]-(0)-|   (active, names: '|':UIStackView:0x13bf2c220 )>",
    "<NSLayoutConstraint:0x2835dd590 'UISV-spacing' V:[UIStackView:0x1261431c0]-(16)-[UIStackView:0x1093d6f70]   (active)>",
    "<NSLayoutConstraint:0x283687840 'UISV-spacing' V:[UIStackView:0x13bf201f0]-(0)-[UIStackView:0x13bf2c220]   (active)>",
    "<NSLayoutConstraint:0x2835dcbe0 'UISV-spacing' V:[UIStackView:0x1261ea210]-(16)-[UIStackView:0x12611ebc0]   (active)>",
    "<NSLayoutConstraint:0x2835dc870 'UISV-spacing' V:[UIStackView:0x12611ebc0]-(16)-[UIStackView:0x1261c5c30]   (active)>",
    "<NSLayoutConstraint:0x2835dd310 'UISV-spacing' V:[UIStackView:0x1261c5c30]-(16)-[UIStackView:0x1261431c0]   (active)>",
    "<NSLayoutConstraint:0x2835ecfa0 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x13bf228b0.height == 60.5   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x2835dd590 'UISV-spacing' V:[UIStackView:0x1261431c0]-(16)-[UIStackView:0x1093d6f70]   (active)>

セルの高さは tableView.rowHeight にUITableView.automaticDimension、tableView.estimatedRowHeight に 0 以外の値を設定することで、Self sizing 機能により自動で算出するようにしている。

tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 60

エラーメッセージに出ているUIView-Encapsulated-Layout-Heightというのはこの Self sizing によりシステムで自動で算出されて追加された高さの制約。

またセルタップ時の高さ変更には tableView.performBatchUpdates (iOS 11.0以降)を使い、その中で isHidden プロパティを変更している。

tableView.performBatchUpdates({
    // toggleメソッド内で isHidden プロパティの変更をしている
    (tableView.cellForRow(at: indexPath) as? MyTableViewCell)?.toggle()
}, completion: nil)

このエラーの対応としては、vertical な UIStackView の Bottom と、親ビュー contentView の bottom との関係をGreater Than or Equalで、priority 1000 の制約にしていたが、これを999にして優先度を下げることにより、制約がbreakingするエラーが出なくなった。