I am having trouble getting my UITableView to appear full height in my Stack View.
My view tree looks as follows:
- View
- Scroll View
- Stack View
- Table View
- Image View
- Map View
The table view is dynamically populated with data, which works fine. The issue is that only one row is visible at a time and I have to scroll through the list. What I would like to see happen is for the table view to take as much vertical room as it needs to display all the cells.
I did try adjusting table height as follows, but that just ends up with table that no longer scrolls, though even if it did work I would rather have something more dynamic:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.detailsTableView.frame.size.height = 200
}
I am suspecting that it is probably an aspect of the 'stack view' that needs adjusting, but I am not sure at this point. Can anyone suggest an appropriate way?
Select the top-level stack view and in the Attributes inspector, click the + button next to Spacing: Choose Any Width and Compact Height, then select Add Variation. Set the Spacing to 10 in the new hC field: Build and run.
There are two main base ways to populate a tableview. The more popular is through Interface Building, using a prototype cell UI object. The other is strictly through code when you don't need a prototype cell from Interface Builder.
The way I achieve adding spacing between cells is to make numberOfSections = "Your array count" and make each section contains only one row. And then define headerView and its height. This works great.
I had been encountering the same issue and realized you need a self sizing table view. I stumbled on this answer and created a subclass like @MuHAOS suggested. I did not encounter any issues.
final class IntrinsicTableView: UITableView {
override var contentSize: CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
A UIStackView will compress views wherever it can, to counteract this set a height anchor and width anchor to the UITableView or a priority for its height and width. Here is a working example of how we can be in charge of the dimensions of a table within a stack view.
First of all I've written a UIStackView extension so that I don't need to include all the code inside the view controller. Your positioning and setup will be different because you are placing your stack view inside a scroll view, but separating this code out means you can make your own adjustments.
extension UIStackView {
convenience init(axis:UILayoutConstraintAxis, spacing:CGFloat) {
self.init()
self.axis = axis
self.spacing = spacing
self.translatesAutoresizingMaskIntoConstraints = false
}
func anchorStackView(toView view:UIView, anchorX:NSLayoutXAxisAnchor, equalAnchorX:NSLayoutXAxisAnchor, anchorY:NSLayoutYAxisAnchor, equalAnchorY:NSLayoutYAxisAnchor) {
view.addSubview(self)
anchorX.constraintEqualToAnchor(equalAnchorX).active = true
anchorY.constraintEqualToAnchor(equalAnchorY).active = true
}
}
We don't set a size for the UIStackView only a position, it is the things contained within it that determine its size. Also note the setting of translatesAutoresizingMaskIntoConstraints
to false in the UIStackView extension. (It is only required that we set this property for the stack view, its subviews simply inherit the behaviour.)
Next I've created a basic table class for demo purposes.
class MyTable: UITableView, UITableViewDataSource {
let data = ["January","February","March","April","May","June","July","August","September","October","November","December"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SauceCell", forIndexPath: indexPath)
cell.textLabel?.text = data[indexPath.row]
return cell
}
}
Finally, the important stuff. As soon as we add our table to the stack view all the frame information is disregarded. So we need the final two lines of code to set the width and height for the table in terms that Auto Layout can understand.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let table = MyTable(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
table.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SauceCell")
table.dataSource = table
let stack = UIStackView(axis: .Vertical, spacing: 10)
stack.anchorStackView(toView: view, anchorX: stack.centerXAnchor, equalAnchorX: view.centerXAnchor, anchorY: stack.centerYAnchor, equalAnchorY: view.centerYAnchor)
stack.addArrangedSubview(table)
table.widthAnchor.constraintEqualToAnchor(view.widthAnchor, multiplier: 1).active = true
table.heightAnchor.constraintEqualToAnchor(view.heightAnchor, multiplier: 0.5).active = true
}
}
Note that we use addArrangedSubview:
not addSubview:
when adding views to the stack view.
(I've written blogposts about UIStackView as well as others about Auto Layout in general that might help too.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With