If you like to try the source code (which you are very welcome to do), have a look at my Bitbucket repository.
I have a popover dialogue that shows a list of settings. These settings a listed inside multiple UITableViews. The UITableViews shall not be scrollable, for the overall settings view already is. Furthermore, the popover dialogue shall take as much screen vertically as it needs but shall be horizontally compressed.
Thus, I conceived the following structure:
UIView => MySettingsViewController
- UIScrollView
- UIView (Content View)
- Container View1
- UITableView (embedded) => MyTableViewController
- Container View2
- UITableView (embedded)
The structure is assembled via Interface Builder and Autolayout is used for the sizing.
I have both the Scroll View, the Content View (I started with just one) and the Container View to their respective superviews (or layout guides). I constrained the size of the content view in the following manner:
contentView.width == (topmost) UIView.width
contentView.height == 200 // removed at build time
Additionally, I set the size of the table view to its content size, because otherwise the popover appears to be empty:
class MyTableViewController: UITableViewController {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// this is Cartography syntax - the intention should be clear
layout(view, replace: ConstraintGroup()) { [unowned self] view in
view.width == self.tableView.contentSize.width
view.height == self.tableView.contentSize.height
}
view.setNeedsLayout()
}
}
The settings popover is filled with content, but its size is not quite right:
To fix this, I tried the following approach which does not work:
class MySettingsViewController: UIViewController {
override var preferredContentSize: CGSize {
get {
let compressedSize = view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
// this is always (0, 0) because the subviews are not resized, yet
return compressedSize
}
set {
super.preferredContentSize = newValue
}
}
}
To conclude: The compression does not work.
So I just fixed the problem myself as you can see when looking at the Bitbucket repository.
The layout is now fixed both in
MyTableViewController
andMySettingsViewController
. The former one now looks like this:So basically, I constraint the height of the table to its content's height and change the constraint if the content's height changes. This is done as soon as the table is laid out. Furthermore, the nested table view is pinned by its edges to the edges of the container view. I think that this is mandatory because I could not find out how to constrain two views of different scenes right in Interface Builder.
In
MySettingsViewController
the scrollview's size is set to the size of the content view's frame (which is accessible via an outlet) as soon as this size is known. Furthermore, to make the popover compress, the preferredContentSize of the settings controller is adapted accordingly, when the height changes (if you omit the condition you might get yourself in a layout endless loop. Furthermore I did 3 things to make it possible to have a navigation controller wrapped around MySettingsViewController:Here is the code:
And this is the result: