You'll need to decide on some additional logic - as in, what to do when there are too many rows in the top table view, but this is one approach:
Use this custom table view class (from https://stackoverflow.com/a/48623673/6257435):
final class ContentSizedTableView: UITableView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
This will "auto-size" your table view whenever the content size changes. To use it, add a table view and set its class to ContentSizedTableView.
- Constrain the top, leading and trailing as desired.
- Constrain the bottom to the top of the bottom table view.
- Give it a height constraint - doesn't really matter what, but using
200 let's you work with the layout. But... edit that height constraint and check the Placeholder - Remove at build time checkbox.
- Constrain the bottom table view to leading, trailing and bottom as desired.
Now, when you add rows to the top table view, it will auto-expand vertically, and the bottom table view will auto-contract vertically (until it disappears). Because the bottom of the top table view is still constrained to the top of the bottom table view, the top table view will stop growing and be scrollable (instead of extending off the bottom of the view).
Here's a very simple example:
import UIKit
final class ContentSizedTableView: UITableView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
class SimpleTopCell: UITableViewCell {
@IBOutlet var theLabel: UILabel!
}
class SimpleBottomCell: UITableViewCell {
@IBOutlet var theLabel: UILabel!
}
class AutoSizeTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet var topTableView: ContentSizedTableView!
@IBOutlet var bottomTableView: UITableView!
var numRowsTop = 8
var numRowsBottom = 12
override func viewDidLoad() {
super.viewDidLoad()
topTableView.dataSource = self
bottomTableView.dataSource = self
topTableView.delegate = self
bottomTableView.delegate = self
}
@IBAction func addRowTapped(_ sender: Any) {
numRowsTop += 1
topTableView.reloadData()
}
@IBAction func delRowTapped(_ sender: Any) {
numRowsTop -= 1
// make sure it's at least 1
numRowsTop = max(numRowsTop, 1)
topTableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == topTableView {
return numRowsTop
}
return numRowsBottom
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == topTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "SimpleTopCell", for: indexPath) as! SimpleTopCell
cell.theLabel.text = "Top: \(indexPath)"
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "SimpleBottomCell", for: indexPath) as! SimpleBottomCell
cell.theLabel.text = "Bottom: \(indexPath)"
return cell
}
}
With 8 rows in the top, and 12 rows in the bottom, we get:

and with 11 rows in the top:

and finally with 17 rows in the top (scrolled so you can see):

Here is the storyboard source for that example:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Qun-XE-Shi">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Auto Size Table View Controller-->
<scene sceneID="fo7-Cf-tO5">
<objects>
<viewController id="Qun-XE-Shi" customClass="AutoSizeTableViewController" customModule="XC10SWScratch" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Vvb-uu-phq">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="uEB-QI-6Jy">
<rect key="frame" x="87.5" y="44" width="200" height="30"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qaz-hh-38L">
<rect key="frame" x="0.0" y="0.0" width="85" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Add Row"/>
<connections>
<action selector="addRowTapped:" destination="Qun-XE-Shi" eventType="touchUpInside" id="01O-ew-Ezw"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aEk-df-qAr">
<rect key="frame" x="115" y="0.0" width="85" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Del Row"/>
<connections>
<action selector="delRowTapped:" destination="Qun-XE-Shi" eventType="touchUpInside" id="qXr-S1-utk"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="width" constant="200" id="zau-ia-umI"/>
</constraints>
</stackView>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="2Kp-ZU-yGW" customClass="ContentSizedTableView" customModule="XC10SWScratch" customModuleProvider="target">
<rect key="frame" x="40" y="100" width="295" height="240"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="240" placeholder="YES" id="BHc-OJ-3pa"/>
</constraints>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SimpleTopCell" id="TcM-H4-6wf" customClass="SimpleTopCell" customModule="XC10SWScratch" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="295" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="TcM-H4-6wf" id="Zvz-a3-fip">
<rect key="frame" x="0.0" y="0.0" width="295" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VZP-Nh-tor">
<rect key="frame" x="15" y="11" width="265" height="22"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="VZP-Nh-tor" firstAttribute="top" secondItem="Zvz-a3-fip" secondAttribute="topMargin" id="0CD-yt-vZ5"/>
<constraint firstItem="VZP-Nh-tor" firstAttribute="leading" secondItem="Zvz-a3-fip" secondAttribute="leadingMargin" id="7LB-3U-q99"/>
<constraint firstAttribute="trailingMargin" secondItem="VZP-Nh-tor" secondAttribute="trailing" id="Pp4-PA-tvk"/>
<constraint firstItem="VZP-Nh-tor" firstAttribute="bottom" secondItem="Zvz-a3-fip" secondAttribute="bottomMargin" id="xP2-ad-aPi"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="theLabel" destination="VZP-Nh-tor" id="aiq-L8-DYT"/>
</connections>
</tableViewCell>
</prototypes>
</tableView>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="UCl-gz-0HT">
<rect key="frame" x="40" y="360" width="295" height="287"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SimpleBottomCell" id="PtI-n4-c5u" customClass="SimpleBottomCell" customModule="XC10SWScratch" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="295" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="PtI-n4-c5u" id="bCo-w1-VQ7">
<rect key="frame" x="0.0" y="0.0" width="295" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Inu-NF-CgL">
<rect key="frame" x="15" y="11" width="265" height="22"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="Inu-NF-CgL" firstAttribute="bottom" secondItem="bCo-w1-VQ7" secondAttribute="bottomMargin" id="2Nz-Y2-ceX"/>
<constraint firstItem="Inu-NF-CgL" firstAttribute="leading" secondItem="bCo-w1-VQ7" secondAttribute="leadingMargin" id="HIx-hC-b4c"/>
<constraint firstItem="Inu-NF-CgL" firstAttribute="top" secondItem="bCo-w1-VQ7" secondAttribute="topMargin" id="Xfn-2l-Dyw"/>
<constraint firstAttribute="trailingMargin" secondItem="Inu-NF-CgL" secondAttribute="trailing" id="f8F-YZ-jJh"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="theLabel" destination="Inu-NF-CgL" id="fsi-1C-DCU"/>
</connections>
</tableViewCell>
</prototypes>
</tableView>
</subviews>
<color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="UCl-gz-0HT" firstAttribute="top" secondItem="2Kp-ZU-yGW" secondAttribute="bottom" constant="20" id="2Kx-3i-Hd9"/>
<constraint firstItem="PTh-mY-2F7" firstAttribute="bottom" secondItem="UCl-gz-0HT" secondAttribute="bottom" constant="20" id="D50-Uk-fN0"/>
<constraint firstItem="PTh-mY-2F7" firstAttribute="trailing" secondItem="2Kp-ZU-yGW" secondAttribute="trailing" constant="40" id="F1H-8j-bVy"/>
<constraint firstItem="PTh-mY-2F7" firstAttribute="trailing" secondItem="UCl-gz-0HT" secondAttribute="trailing" constant="40" id="KXW-yh-GAA"/>
<constraint firstItem="uEB-QI-6Jy" firstAttribute="top" secondItem="PTh-mY-2F7" secondAttribute="top" constant="24" id="M5V-JO-Jfw"/>
<constraint firstItem="uEB-QI-6Jy" firstAttribute="centerX" secondItem="Vvb-uu-phq" secondAttribute="centerX" id="TlF-gf-jKf"/>
<constraint firstItem="2Kp-ZU-yGW" firstAttribute="top" secondItem="PTh-mY-2F7" secondAttribute="top" constant="80" id="XFo-ry-u9Y"/>
<constraint firstItem="2Kp-ZU-yGW" firstAttribute="leading" secondItem="PTh-mY-2F7" secondAttribute="leading" constant="40" id="iu7-sU-Gki"/>
<constraint firstItem="UCl-gz-0HT" firstAttribute="leading" secondItem="PTh-mY-2F7" secondAttribute="leading" constant="40" id="ni9-df-1kD"/>
</constraints>
<viewLayoutGuide key="safeArea" id="PTh-mY-2F7"/>
</view>
<navigationItem key="navigationItem" id="6mN-ug-bQV"/>
<connections>
<outlet property="bottomTableView" destination="UCl-gz-0HT" id="Yny-Gc-zhG"/>
<outlet property="topTableView" destination="2Kp-ZU-yGW" id="puB-6Z-xMa"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="kps-Ns-Nci" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1088.8" y="2196.2518740629689"/>
</scene>
</scenes>
</document>