Last week, a refresh of the design of my client's app called for a layout that changed depending on the device orientation. We're using AutoLayout and didn't want to use any deprecated methods.
Problem was that it called for layout changes within a UITableViewCell. I thought of a way to do this with AutoLayout but the constraints would become quite complex. Instead, I took the following approach:
- Create a custom UITableViewCell by subclassing it
- To this subclass, add outlets for the constraints that you want to influence
- In the view controller, detect whether we're in portrait or landscape, then update the constraints of the cells using the IBOutlet properties
Thus the UITableViewCell subclass looks as follows:
class CustomTableCell : UITableViewCell {
@IBOutlet weak var dateLabel: UILabel!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var trailingConstraint: NSLayoutConstraint!
}
Problem is: where can you set properties all the currently visible cells? The easiest way I could come up with, is in the cellForRowAtIndexPath() function. The view controller class has the following property:
var size: CGSize = CGSizeZero
The viewWillTransitionToSize() function stores the new screen size and asks the UITableView to reload:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
self.size = size
NSLog("viewWillTransitionToSize self.size = \(self.size)")
self.tableView!.reloadData()
}
And when dequeueing new cells, we set the constraint its constant:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TestCell") as CustomTableCell!
NSLog("self.size=\(self.size)")
cell.nameLabel.text = self.items[indexPath.row]
if self.size.width > self.size.height { //Landscape
NSLog("Landscape")
cell.trailingConstraint.constant = 100
} else { //Portrait
NSLog("Portrait")
cell.trailingConstraint.constant = 0
}
return cell
}
Because viewWillTransitionToSize() is not called when the View Controller is run for the first time, I also added the following code to viewWillLayoutSubviews():
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// Only run once, upon first display
if self.size == CGSizeZero {
self.size = self.tableView!.frame.size
NSLog("viewWillLayoutSubviews self.size = \(self.size)")
}
}
Result:

Download the example project: TestTableViewCellSizing.zip
Note: I created the above truly breathtaking animated gif by taking a screen recording with QuickTime Player, running the iOS Simulator, then converting the resulting .mov file with the following ffmpeg command:
ffmpeg -i example.mov -r 15 example.gif
ffpmeg was installed via Homebrew.