UIStackView is not updated after updating the height of the preview (UITableView without scrolling), but inside ScrollView

How to make UIStackView redistribute it under UITableViews while the stackView is inside the scroll?

My layout hierarchy is based on the official documentation from apple about Dynamic Content for StackViews

  - UISCrollView - UIStackView - UIView A - UIView B - UIView C - UITableView X - UITableView Y - UIView D 

Limitations are set as documented. The initial layout of StackView is correct, showing all visible subzones. When forced to allow normal views to extend beyond the height of the screen, scrolling works as expected. Also, when viewing the layout in the storyboard, everything stacks up as expected.
At this point, the UITableView empty. As soon as I add content to the View table, a problem will appear.

Problem
When I dynamically update the TableView by calling .reloadData() on both of them, I see their contents. ( due to this answer about the lack of scrolling tableViews), but UIStackView does not stack UITableViews.

  • UIView D falls below UIView C
  • UITableView X and UITableView Y also located below UIView B

I assume that I need to invalidate the stack view or somehow force it to redistribute it as subviews. How can i do this?

enter image description here

+5
source share
1 answer

First, a warning:

What you are trying to achieve is not standard iOS behavior. You should first consider another approach, like creating a single, grouped table view with several sections. You can implement custom views within your table view as headers or section footers.


Now, if you really want to go with your original approach ...

... for some important reason, you should know that by default there is no internal content to represent the table. Thus, you need to say that the table should look so high, because otherwise it will only decrease to zero height.

You can achieve this by either subclassing the UITableView or overriding its intrinsicContentSize() , as Rob suggests in this answer to a similar question.

Or you add a height constraint to each of the table views and dynamically set your constants in the code. Quick example:

  • Add both table views to the vertical stack view in Interface Builder.
  • Give both tabular views the leading and final constraints to bind their left and right edges to the stack view.
  • Create output points for the presentation of tables in the appropriate view controller:

     @IBOutlet weak var tableView1: UITableView! @IBOutlet weak var tableView2: UITableView! @IBOutlet weak var tableView1HeightConstraint: NSLayoutConstraint! @IBOutlet weak var tableView2HeightConstraint: NSLayoutConstraint! 
  • Cancel the updateViewConstraints() method of this controller:

     override func updateViewConstraints() { super.updateViewConstraints() tableView1HeightConstraint.constant = tableView1.contentSize.height tableView2HeightConstraint.constant = tableView2.contentSize.height } 
  • Now, when the contents of any of your table views change (for example, when you add or delete rows or change the contents of a cell), you need to tell the controller of your view that it needs to update its restrictions. Let's say you have a button that adds a cell to tableView1 every time you click it. You can implement its action as follows:

     @IBAction func buttonTappen(sender: AnyObject) { // custom method you implement somewhere else in your view controller addRowToTableView1DataSource() // reload table view with the updated data source tableView1.reloadData() // triggers an updateViewConstraints() call view.setNeedsUpdateConstraints() } 

TL; dr:

A UITableView not intended to be used without scrolling, and therefore you always need to explicitly set its height when its contents change - it may use restrictions or override the internal size of the table contents.

+3
source

All Articles