Usually we use UIViewController for many cases, but sometime there is a time that we want app that support vertical-view on iPhone.
As I mention at the title we gonna use UITableViewController, but not using any table view features, but really just layout everything on the storyboard.
Reasons to use UITableViewController over UIViewController
Let’s create a new single view project from the template, it has ViewController.swift as default which subclass to UIViewController
.
Open the Main.storyboard and make a layout something like this.
But suddenly we want to add support for vertical. Should we embeded in UIScrollView and define contentSize? I can be really hard if we have complex auto-layout constraints among the subviews.
With all autolayout take in place you can imaging how hard to add into UIScrollView, and ContentView and have the auto layout contraint work in place.
Revision: UIScrollView is a view that is adjustable over the content view. It clips the content to its frame. There is 2 minimum condition to met to make UIScrollView working. The frame of UIScollView and the contentSize so it knows when to stop scrolling.
Lets be honest, we don’t intend at the begininig to use UITableViewController, but when we have to support vertical orientation for small iPhone screen, it can not be scrollable automatically. The view is created with UIViewController. The class that it referst also a UIViewController.
At storyboard, drag UITableViewController into the storybaord nearby the UIViewController that we want to replace.
Select the Table View, set it Content as Static Cells.
Delete ‘Table View Section’ that come with it.
The Original View Controlle already has the autolayout set in place, designed with iPhone 7 layout, so when we run on iPhone 7 Plus it will look like this.
The problem is just don’t scroll down.
Now drag the view from the original view controller to the table view.
So the UITableView will have a header view from the original UIViewController when we drag-drop like that.
Now to to ViewController.swift, change the super class like this.
class ViewController: UITableViewController {
....
}
At the storyboard, change the initial view view controller to the new Table View, set the view controller class to ViewController.
Initial Issue
When testing on vertical mode, we will get the view get clipped. It’s not okay because we cannot see the whole view. So we have to code something inside the UITableViewController subclass, ViewController.swift.
Let’s make an IBOutlet reference from the UITableView’s view as contentView
, like the image below.
Next, is to open the inspector to see at the storyboard and see height of the ‘contentView’ view. We will use the value to hard-code inside the code.
Currently, it’s hard to get the height when we open the app with landscape mode, that’s why we don’t have choise but to copy the height. It works anyway.
At ViewController.swift, add this variable declaration.
// Add this at class declaration
let contentViewHeight:CGFloat = <#View-height#>
Add a override function of viewWillLayoutSubivews().
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// This will let the our view view not being clipped
// and also by setting tableView content size make it scrollable
let size = CGSizeMake(self.view.frame.width, contentViewHeight)
contentView.frame.size = size
tableView.contentSize = size
}
P/S: Embedded in UINavigationController
We also tested it embeded with UINavigationController, which is also fine with Xcode 8. Previous version of Xcode need to add something inside the viewWillLayoutSubivews.
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// This will help with over padding issue if you
// embedded inside navigation controller
if (self.view.frame.origin.y == 0) {
if let rect = self.navigationController?.navigationBar.frame {
let y = rect.size.height + rect.origin.y
self.tableView.contentInset = UIEdgeInsetsMake(y, 0, 0, 0)
}
} else if ( self.view.frame.origin.y == 44 || self.view.frame.origin.y == 64) {
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
// This will let the our view view not being clipped
// and also by setting tableView content size make it scrollable
let size = CGSize(width:self.view.frame.width, height:contentViewHeight)
contentView.frame.size = size
tableView.contentSize = size
}