How to design a dynamic layout with two TableViews in Swift(如何在 Swift 中使用两个 TableView 设计动态布局)
问题描述
各位程序员们好.
我花了很多时间尝试在 Swift 中设计这种布局,但收效甚微.
顶部有 11 行:
最后在顶部有 17 行(滚动以便您可以看到):
这是该示例的情节提要源代码:
<?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"><设备id="retina4_7"orientation="portrait"><适应 id="全屏"/></设备><依赖关系><plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/><capability name="安全区域布局指南" minToolsVersion="9.0"/><capability name="Xcode 8 格式保存的文档" minToolsVersion="8.0"/></依赖关系><场景><!--自动尺寸表视图控制器--><场景sceneID="fo7-Cf-tO5"><对象><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"/><子视图><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"/><子视图><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="正常" title="添加行"/><连接><action selector="addRowTapped:" destination="Qun-XE-Shi" eventType="touchUpInside" id="01O-ew-Ezw"/></连接></按钮><button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aEk-df-qAr">
Hi fellow programmers.
I've spent many hours trying to design this layout in Swift, with little success.
Drawing of the layout
The idea is having two TableViews:
- The top one, with zero or more (indefined) cells, which can't be scrollable and its height grows with the number of cells.
- The bottom one, with zero or more (indefined) cells, which is scrollable, and thus its height adapts to the space left from the latter tableview.
I've already tried to play with the constraints programmatically, by setting both tables top constraint to the top of the screen and then modifying that constraint depending on the size of the top TableView. Doesn't seem to work.
I also tried to modify the height of the tables programmatically, based on the number of cells that will be draw. Didn't work either.
Honestly, I'm at a deadpoint right now, and I'm looking out for help or some new ideas to make it work. Any help will be highly appreciated. Thanks in advance!
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>
这篇关于如何在 Swift 中使用两个 TableView 设计动态布局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在 Swift 中使用两个 TableView 设计动态布局
基础教程推荐
- 当从同一个组件调用时,两个 IBAction 触发的顺序是什么? 2022-01-01
- 如何在 UIImageView 中异步加载图像? 2022-01-01
- Kivy Buildozer 无法构建 apk,命令失败:./distribute.sh -m “kivy"d 2022-01-01
- 如何让对象对 Cocos2D 中的触摸做出反应? 2022-01-01
- android 应用程序已发布,但在 google play 中找不到 2022-01-01
- 如何在没有IB的情况下将2个按钮添加到右侧的UINavigationbar? 2022-01-01
- Android:对话框关闭而不调用关闭 2022-01-01
- 在 gmail 中为 ios 应用程序检索朋友的朋友 2022-01-01
- 如何在 iPhone 上显示来自 API 的 HTML 文本? 2022-01-01
- UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效? 2022-01-01