先週の勉強会#swiftwozに来てくださった方ありがとうございました。自分のパートは準備不足ですみませんでした。何人かの方にGithubのswift-layoutを使っていただき、重ね重ねありがとうございます。
今日はUITableViewのcellでAuto Layoutを使ってみました。
このようなケースを想定しています。
- UITableViewに各行で異なる高さのUITableViewCellを表示
- CellのレイアウトはAuto Layoutで設定
- CellはdequeueReusableCellWithIdentifierでキャッシュされたものを使う
UITableViewCellのcontentViewにAuto Layoutで書いたsubviewを入れても、なぜかcontentViewの高さが変更されないところではまりました。setNeedsLayou(),layoutIfNeede(),layoutSubviews()あたりを使っても高さが変わらなかったので、subviewのboundsから高さを直接計算してheightForRowAtIndexPathの戻り値にしているところがポイントです。
また、heightForRowAtIndexPathメソッド内で高さを計算する時に、tableView.dequeueReusableCellWithIdentifier("MyTableViewCell", forIndexPath: indexPath)を使用すると実行時に落ちるので、高さ計算用のCellインスタンス(tmpCalculatHeightCell)を一つ用意しています。
サンプルコードは、Auto Layoutをラップしたswift-layoutを使用していますが、直接NSLayoutConstraintを使用しても動くはずです。
コード
https://github.com/grachro/DEMO-Swift-AutoLayout-ResizableTableViewCell
全文
import UIKit class ViewController: UIViewController { let tableView = UITableView() var tmpCalculatHeightCell:MyTableViewCell? override func viewDidLoad() { super.viewDidLoad() //Auto Layout Layout.regist(tableView,superview: self.view) .coverSuperView() self.tableView.registerClass(MyTableViewCell.self, forCellReuseIdentifier: "MyTableViewCell") self.tableView.dataSource = self self.tableView.delegate = self } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } } extension ViewController:UITableViewDataSource { func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 50 } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cell = self.tableView.dequeueReusableCellWithIdentifier("MyTableViewCell", forIndexPath: indexPath) as MyTableViewCell let containtHeight = CGFloat(indexPath.row + 1) * 5 cell.setHeight(containtHeight) return cell } } extension ViewController:UITableViewDelegate { func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { let containtHeight = CGFloat(indexPath.row + 1) * 5 if self.tmpCalculatHeightCell == nil { self.tmpCalculatHeightCell = self.tableView.dequeueReusableCellWithIdentifier("MyTableViewCell") as? MyTableViewCell } if let cell = self.tmpCalculatHeightCell as MyTableViewCell! { cell.setHeight(containtHeight) cell.setNeedsLayout() cell.layoutIfNeeded() return cell.totalCellHeight } return 0 } } class MyTableViewCell : UITableViewCell { var widthConstraint: NSLayoutConstraint? var heightConstraint: NSLayoutConstraint? var baseViewLayout:Layout? var resizableViewLayout:Layout? override init(style: UITableViewCellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) self.contentView.backgroundColor = UIColor.redColor() //Auto Layout self.baseViewLayout = Layout.registUIView(superview: self.contentView) .widthIsSame(self.contentView) //Auto Layout self.resizableViewLayout = Layout.registUIView(superview: self.baseViewLayout!.view) .top(10).fromSuperviewTop() .bottom(10).fromSuperviewBottom() .width(0).lastConstraint(&widthConstraint) .height(0).lastConstraint(&heightConstraint) .horizontalCenterInSuperview() .backgroundColor(UIColor.yellowColor()) } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setHeight(height:CGFloat) { self.widthConstraint?.constant = height self.heightConstraint?.constant = height } var totalCellHeight:CGFloat { return baseViewLayout!.view.bounds.height } }