使用 UITableViewAutomaticDimension 制作带有嵌入式 UICollectionView 的 UITableView [英] Making UITableView with embedded UICollectionView using UITableViewAutomaticDimension
问题描述
我想使用 UITableViewAutomaticDimension
创建一个带有标题标签的 UITableView
和嵌入的 UICollectionView
(知道它的大小)和一些图标.问题是当我有 UICollectionView
时,UITableView
在计算单元格高度时出现问题.我必须滚动 UITableView
才能重新计算大小.但即便如此,它也存在高度问题(如果从较大的高度重复使用它太大了).最重要的是 UICollectionView
内的图标从乞讨中不知道,但它们旨在从服务器加载.
我还尝试为 UICollectionView
创建高度约束,但这样我得到无法同时满足约束",这是由于与 UIView-Encapsulated-Layout 冲突而导致的-Height
反正我自己的约束被移除了.
我已经创建了一个带有示例项目的 GitHub 存储库(我做得尽可能简单):
这是输出
希望对你有帮助
编辑/更新
您的演示项目中有很多问题.我对你的演示项目做了很多改动.
将 XML
复制并粘贴到情节提要中.
别忘了连接高度约束
这里是完整的故事板XML
<?xml version="1.0" encoding="UTF-8"?><document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"><设备id="retina4_7"orientation="portrait"><适应 id="全屏"/></设备><依赖关系><部署标识符="iOS"/><plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/><capability name="安全区域布局指南" minToolsVersion="9.0"/><capability name="Xcode 8 格式保存的文档" minToolsVersion="8.0"/></依赖关系><场景><!--查看控制器--><场景场景ID="tne-QT-ifu"><对象><viewController id="BYZ-38-t0r" customClass="ViewController" customModule="CollectionViewInTableView" customModuleProvider="target" sceneMemberID="viewController"><view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"><rect key="frame" x="0.0" y="0.0" width="375" height="667"/><autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/><子视图><tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="196" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="ZhZ-if-Yia"><rect key="frame" x="0.0" y="0.0" width="375" height="667"/><color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/><原型><tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" rowHeight="196" id="1WO-2S-MI9" customClass="FooTableViewCell" customModule="CollectionViewInTableView" customModuleProvider="target"><rect key="frame" x="0.0" y="28" width="375" height="196"/><autoresizingMask key="autoresizingMask"/><tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="1WO-2S-MI9" id="2lF-aM-Z2U"><rect key="frame" x="0.0" y="0.0" width="375" height="195.5"/><autoresizingMask key="autoresizingMask"/><子视图><label opaque="NO" userInteractionEnabled="NO" contentMode="left" HorizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit=NO"翻译AutoresizingMaskIntoConstraints="NO" id="vs4-91-woo"><rect key="frame" x="8" y="8" width="359" height="20.5"/><fontDescription key="fontDescription" type="system" pointSize="17"/><nil key="textColor"/><nil key="highlightedColor"/></标签><label opaque="NO" userInteractionEnabled="NO" contentMode="left" HorizontalHuggingPriority="251" verticalHuggingPriority="251" text="Description" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit=NO"翻译AutoresizingMaskIntoConstraints="NO" id="lD2-bR-lnm"><rect key="frame" x="8" y="36.5" width="359" height="20.5"/><fontDescription key="fontDescription" type="system" pointSize="17"/><nil key="textColor"/><nil key="highlightedColor"/></标签><collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="6sQ-gf-Y6x" customClass="IconsCollectionView" customModule="CollectionViewInTableView" customModuleProvider="目标"><rect key="frame" x="8" y="65" width="359" height="92.5"/><color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/><约束><约束 firstAttribute="height" 关系="greaterThanOrEqual" priority="750" constant="88" id="f9g-Du-pYg"/></约束><collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="Nts-Lf-FPD">
FOOTableviewCell.swift
协议 TableViewDelegate {func cellTapped (for:FooTableViewCell)}类 FooTableViewCell: UITableViewCell {静态让 singleCellHeight = 88;@IBOutlet 弱变量标题标签:UILabel!@IBOutlet 弱变量描述标签:UILabel!@IBOutlet 弱 var iconsCollectionView:IconsCollectionView!@IBOutlet 弱变量 const_Height_CollectionView:NSLayoutConstraint!var delegateCollection:TableViewDelegate?可变酒吧:[酒吧] = [] {设置{self.iconsCollectionView.reloadData()图标CollectionView.setNeedsLayout()self.layoutIfNeeded()const_Height_CollectionView.constant = iconsCollectionView.contentSize.heightself.layoutIfNeeded()}}覆盖 func awakeFromNib() {iconsCollectionView.translatesAutoresizingMaskIntoConstraints = falseiconsCollectionView.initFlowLayout(superviewWidth: self.frame.width)图标CollectionView.setNeedsLayout()图标CollectionView.dataSource = self图标CollectionView.delegate = selfconst_Height_CollectionView.constant = iconsCollectionView.contentSize.heightself.layoutIfNeeded()self.setNeedsLayout()}func cellTapped () {图标CollectionView.setNeedsLayout()self.layoutIfNeeded()self.setNeedsLayout()const_Height_CollectionView.constant = iconsCollectionView.contentSize.heightself.delegateCollection?.cellTapped(for: self)}}扩展 FooTableViewCell : UICollectionViewDataSource {func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) ->诠释{返回 bar.count + 1}func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) ->UICollectionViewCell {让 cell = collectionView.dequeueReusableCell(withReuseIdentifier: "item", for: indexPath) as!BarCollectionViewCell让行 = indexPath.row如果(行> = bar.count){cell.iconImageView.image = UIImage(named: "add.png")返回单元格} 别的 {让酒吧 = 酒吧 [行]cell.iconImageView.image = UIImage(命名:bar.imageName)打印(bar.imageName)返回单元格}}}扩展 FooTableViewCell : UICollectionViewDelegate {func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {//取消选择项(在:indexPath,动画:真)if(indexPath.row >= bars.count) {//这是一个加号按钮self.delegateCollection?.cellTapped(for: self)}}}
IconCollectionView.swift
导入 UIKit类 IconsCollectionView: DynamicCollectionView {var columnLayout:ColumnFlowLayout?覆盖 func awakeFromNib() {}func initFlowLayout(superviewWidth:CGFloat) {让布局 = ColumnFlowLayout(细胞每行:4,超级视图宽度:超级视图宽度,minimumInteritemSpacing: 0,最小行间距:0,sectionInset:UIEdgeInsets(顶部:0,左侧:0,底部:0,右侧:0))columnLayout = 布局collectionViewLayout = 布局}}
ViewController.Swift
导入 UIKit类视图控制器:UIViewController {@IBOutlet 弱 var tableView:UITableView!var foos:[Foo] = []var 酒吧:[[酒吧]] = [[]]覆盖 func viewDidLoad() {super.viewDidLoad()tableView.dataSource = 自我tableView.delegate = 自我tableView.estimatedRowHeight = 188tableView.rowHeight = UITableViewAutomaticDimensionfor i in stride(from: 1, to: 10, by: 1) {让 foo = Foo()foo.title = "项目(i)"foo.description = "描述 (i)"foos.append(foo)}bar.removeAll()对于 _ in 0 ..<foos.count {bar.append(self.loadIconsSync())}}函数 loadIconsSync() ->[酒吧] {var barObjects :[Bar] = []让 iconsCount = Utils.rnd(3, 8)for _ in stride(from: 1, to: iconsCount, by: 1) {barObjects.append(self.getRandomItem())}返回 barObjects}func getRandomItem() ->酒吧 {让 randomIndex = Utils.rnd(1, 10)让 bar = Bar()bar.imageName = "icon_(randomIndex).png"返回栏}}扩展 ViewController : UITableViewDataSource,UITableViewDelegate {func tableView(_tableView: UITableView, cellForRowAt indexPath: IndexPath) ->UITableViewCell {让 foo = foos[indexPath.row]让 cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as!FooTableViewCellvar bar = bar[indexPath.row]cell.bars = 酒吧cell.titleLabel.text = foo.titlecell.descriptionLabel.text = foo.descriptioncell.delegateCollection = 自我self.view.layoutIfNeeded()cell.const_Height_CollectionView.constant = cell.iconsCollectionView.contentSize.heightself.view.layoutIfNeeded()返回单元格}func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) ->诠释{返回 foos.count}}扩展视图控制器:TableViewDelegate {func cellTapped(for obj: FooTableViewCell) {if let indexPath = tableView.indexPath(for: obj) {bar[indexPath.row].append(getRandomItem())self.tableView.beginUpdates()self.tableView.reloadRows(at: [indexPath], with: .automatic)self.tableView.endUpdates()}}}
输出
编辑/更新 2
我不知道方向支持和 ipad 支持.
现在,当方向改变时,我们必须重新布局集合视图.
所以逻辑是
项目总数 + 1(+ 1 因为那个加号图标)
项目大小 *(项目总数/3).rounded
假设你有 7 个项目
所以项目大小为 93(每行)* ( 8/3).rounded = 279
因此,您需要根据 iPad 和横向模式的要求管理一些硬编码值.现在我正在考虑每行 3 个对象,与 iPhone 设计相同.
这里硬编码的单元格数是3,你可以自己管理.
第一步:
在 viewContorller.swift 中添加 Follow 方法
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {super.viewWillTransition(to: size, with: coordinator)self.tableView.beginUpdates()self.tableView.reloadData()self.tableView.endUpdates()}
替换 cellForRowAtIndexPath
func tableView(_tableView: UITableView, cellForRowAt indexPath: IndexPath) ->UITableViewCell {让 foo = foos[indexPath.row]让 cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as!FooTableViewCellcell.iconsCollectionView.initFlowLayout(superviewWidth: self.tableView.frame.width)让 bar = bar[indexPath.row]cell.bars = 酒吧cell.titleLabel.text = foo.titlecell.descriptionLabel.text = foo.descriptioncell.delegateCollection = 自我self.view.layoutIfNeeded()让项目:CGFloat = CGFloat(bar.count + 1)让值 = (items/3.0).rounded(.awayFromZero)cell.const_Height_CollectionView.constant = CGFloat((cell.iconsCollectionView.collectionViewLayout as!UICollectionViewFlowLayout).itemSize.height * value)self.view.layoutIfNeeded()cell.iconsCollectionView.setNeedsLayout()返回单元格}
还有
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {如果让footCell = cell as?FooTableViewCell {footCell.const_Height_CollectionView.constant = footCell.iconsCollectionView.contentSize.heightself.view.layoutIfNeeded()}}
在 TableviewCell 中
var bar:[Bar] = [] {设置{self.iconsCollectionView.reloadData()图标CollectionView.setNeedsLayout()self.layoutIfNeeded()让项目:CGFloat = CGFloat(bars.count + 1)让值 = (items/3.0).rounded(.awayFromZero)const_Height_CollectionView.constant = CGFloat((iconsCollectionView.collectionViewLayout as!UICollectionViewFlowLayout).itemSize.height * value)self.layoutIfNeeded()}}
和
func cellTapped () {图标CollectionView.setNeedsLayout()self.layoutIfNeeded()self.setNeedsLayout()让项目:CGFloat = CGFloat(bars.count + 1)让值 = (items/3.0).rounded(.awayFromZero)const_Height_CollectionView.constant = CGFloat((iconsCollectionView.collectionViewLayout as!UICollectionViewFlowLayout).itemSize.height * value)self.delegateCollection?.cellTapped(for: self)}
I want to create an UITableView
with Title label and embedded UICollectionView
(which knows it's size) with some icons using UITableViewAutomaticDimension
. The problem is UITableView
has a problem with figuring out cell height when I have UICollectionView
inside. I have to scroll an UITableView
in order for it to recalculate sizes. But even then it has problems with height (it's too big if it was reused from bigger one). On top of that icons inside UICollectionView
aren't known from the begginging, but they are intended to be loaded from the server.
I've also tried to create a height constraint for an UICollectionView
, but this way I'm getting "Unable to simultaneously satisfy constraints" caused by conflict with UIView-Encapsulated-Layout-Height
and my own constraint is being removed anyway.
I've created a GitHub repository with a sample project (I did it as simple as possible):
https://github.com/piotrros/CollectionViewInTableView
As you are doing very much stuff in cellForRow
so it need time to ready and so when you scroll it is not showing properly
Check following things.
ViewController.swift
In View Did load
Add tableView.rowHeight = UITableViewAutomaticDimension
and replace this method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let foo = foos[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FooTableViewCell
cell.titleLabel.text = foo.title
cell.descriptionLabel.text = foo.description
self.view.layoutIfNeeded()
return cell
}
FooTableViewCell.swift
class FooTableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var stackView: UIStackView!
@IBOutlet weak var descriptionLabel: UILabel!
@IBOutlet weak var iconsCollectionView: IconsCollectionView!
@IBOutlet weak var const_Height_CollectionView: NSLayoutConstraint!
override func awakeFromNib() {
iconsCollectionView.translatesAutoresizingMaskIntoConstraints = false
iconsCollectionView.initFlowLayout(superviewWidth: self.frame.width)
iconsCollectionView.loadIconsSync()
iconsCollectionView.setNeedsLayout()
}
}
And I have removed StackView Form your storyboard and just give leading , trailing ,top and bottom constraints (Nothing complicated )
Here is output
Hope it is helpful to you
EDIT/UPDATE
YOu have many issues in your demo project. I have made many changes in your demo project.
Copy and paste XML
in storyboard.
DON'T FORGOT TO CONNECT HEIGHT CONSTRAINT
Here is complete storyboard XML
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="CollectionViewInTableView" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="196" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="ZhZ-if-Yia">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" rowHeight="196" id="1WO-2S-MI9" customClass="FooTableViewCell" customModule="CollectionViewInTableView" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="196"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="1WO-2S-MI9" id="2lF-aM-Z2U">
<rect key="frame" x="0.0" y="0.0" width="375" height="195.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vs4-91-woo">
<rect key="frame" x="8" y="8" width="359" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Description" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lD2-bR-lnm">
<rect key="frame" x="8" y="36.5" width="359" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="6sQ-gf-Y6x" customClass="IconsCollectionView" customModule="CollectionViewInTableView" customModuleProvider="target">
<rect key="frame" x="8" y="65" width="359" height="92.5"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" priority="750" constant="88" id="f9g-Du-pYg"/>
</constraints>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="Nts-Lf-FPD">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="item" id="8gX-Q1-0jG" customClass="BarCollectionViewCell" customModule="CollectionViewInTableView" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="6cf-uD-BQl">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
</imageView>
</subviews>
</view>
<constraints>
<constraint firstAttribute="bottom" secondItem="6cf-uD-BQl" secondAttribute="bottom" id="0c3-ug-8tN"/>
<constraint firstItem="6cf-uD-BQl" firstAttribute="top" secondItem="8gX-Q1-0jG" secondAttribute="top" id="9xW-dN-c0m"/>
<constraint firstItem="6cf-uD-BQl" firstAttribute="leading" secondItem="8gX-Q1-0jG" secondAttribute="leading" id="dT6-RU-eE4"/>
<constraint firstAttribute="trailing" secondItem="6cf-uD-BQl" secondAttribute="trailing" id="nnz-oA-GgP"/>
</constraints>
<connections>
<outlet property="iconImageView" destination="6cf-uD-BQl" id="lFo-SS-Ego"/>
</connections>
</collectionViewCell>
</cells>
</collectionView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sXa-Mn-xxW">
<rect key="frame" x="8" y="165.5" width="359" height="30"/>
<state key="normal" title="Button"/>
</button>
</subviews>
<constraints>
<constraint firstItem="sXa-Mn-xxW" firstAttribute="leading" secondItem="2lF-aM-Z2U" secondAttribute="leading" constant="8" id="4ix-8u-0lO"/>
<constraint firstAttribute="bottom" secondItem="sXa-Mn-xxW" secondAttribute="bottom" id="50m-Bv-FF8"/>
<constraint firstAttribute="trailing" secondItem="sXa-Mn-xxW" secondAttribute="trailing" constant="8" id="8UW-vI-hge"/>
<constraint firstItem="6sQ-gf-Y6x" firstAttribute="leading" secondItem="2lF-aM-Z2U" secondAttribute="leading" constant="8" id="9ht-Ez-lJX"/>
<constraint firstAttribute="trailing" secondItem="vs4-91-woo" secondAttribute="trailing" constant="8" id="NOH-if-o7C"/>
<constraint firstItem="lD2-bR-lnm" firstAttribute="leading" secondItem="2lF-aM-Z2U" secondAttribute="leading" constant="8" id="S2D-Kj-5Og"/>
<constraint firstItem="vs4-91-woo" firstAttribute="leading" secondItem="2lF-aM-Z2U" secondAttribute="leading" constant="8" id="atk-7U-Mrw"/>
<constraint firstAttribute="trailing" secondItem="6sQ-gf-Y6x" secondAttribute="trailing" constant="8" id="bfY-uh-Su2"/>
<constraint firstItem="vs4-91-woo" firstAttribute="top" secondItem="2lF-aM-Z2U" secondAttribute="top" constant="8" id="gYO-XW-lmk"/>
<constraint firstAttribute="trailing" secondItem="lD2-bR-lnm" secondAttribute="trailing" constant="8" id="pkH-Pf-xE1"/>
<constraint firstItem="sXa-Mn-xxW" firstAttribute="top" secondItem="6sQ-gf-Y6x" secondAttribute="bottom" constant="8" id="w2O-4g-q6B"/>
<constraint firstItem="6sQ-gf-Y6x" firstAttribute="top" secondItem="lD2-bR-lnm" secondAttribute="bottom" constant="8" id="xky-sw-IcM"/>
<constraint firstItem="lD2-bR-lnm" firstAttribute="top" secondItem="vs4-91-woo" secondAttribute="bottom" constant="8" id="yG3-dE-CjF"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="const_Height_CollectionView" destination="f9g-Du-pYg" id="gw7-9T-hiU"/>
<outlet property="descriptionLabel" destination="lD2-bR-lnm" id="M4K-k5-6LN"/>
<outlet property="iconsCollectionView" destination="6sQ-gf-Y6x" id="FO2-dP-VNH"/>
<outlet property="titleLabel" destination="vs4-91-woo" id="HHy-1V-bTW"/>
</connections>
</tableViewCell>
</prototypes>
</tableView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="ZhZ-if-Yia" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="J8c-wQ-FxB"/>
<constraint firstItem="ZhZ-if-Yia" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="KCX-nj-zXy"/>
<constraint firstItem="ZhZ-if-Yia" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="QMU-w2-uUY"/>
<constraint firstItem="ZhZ-if-Yia" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="yx7-yg-aqC"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
<connections>
<outlet property="tableView" destination="ZhZ-if-Yia" id="WdR-nu-gjc"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="117.59999999999999" y="118.29085457271366"/>
</scene>
</scenes>
</document>
FOOTableviewCell.swift
protocol TableViewDelegate {
func cellTapped (for:FooTableViewCell)
}
class FooTableViewCell: UITableViewCell {
static let singleCellHeight = 88;
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var descriptionLabel: UILabel!
@IBOutlet weak var iconsCollectionView: IconsCollectionView!
@IBOutlet weak var const_Height_CollectionView: NSLayoutConstraint!
var delegateCollection : TableViewDelegate?
var bars:[Bar] = [] {
didSet {
self.iconsCollectionView.reloadData()
iconsCollectionView.setNeedsLayout()
self.layoutIfNeeded()
const_Height_CollectionView.constant = iconsCollectionView.contentSize.height
self.layoutIfNeeded()
}
}
override func awakeFromNib() {
iconsCollectionView.translatesAutoresizingMaskIntoConstraints = false
iconsCollectionView.initFlowLayout(superviewWidth: self.frame.width)
iconsCollectionView.setNeedsLayout()
iconsCollectionView.dataSource = self
iconsCollectionView.delegate = self
const_Height_CollectionView.constant = iconsCollectionView.contentSize.height
self.layoutIfNeeded()
self.setNeedsLayout()
}
func cellTapped () {
iconsCollectionView.setNeedsLayout()
self.layoutIfNeeded()
self.setNeedsLayout()
const_Height_CollectionView.constant = iconsCollectionView.contentSize.height
self.delegateCollection?.cellTapped(for: self)
}
}
extension FooTableViewCell : UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return bars.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "item", for: indexPath) as! BarCollectionViewCell
let row = indexPath.row
if(row >= bars.count) {
cell.iconImageView.image = UIImage(named: "add.png")
return cell
} else {
let bar = bars[row]
cell.iconImageView.image = UIImage(named: bar.imageName)
print(bar.imageName)
return cell
}
}
}
extension FooTableViewCell : UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//deselectItem(at: indexPath, animated: true)
if(indexPath.row >= bars.count) { //it's a plus button
self.delegateCollection?.cellTapped(for: self)
}
}
}
IconCollectionView.swift
import UIKit
class IconsCollectionView: DynamicCollectionView {
var columnLayout:ColumnFlowLayout?
override func awakeFromNib() {
}
func initFlowLayout(superviewWidth:CGFloat) {
let layout = ColumnFlowLayout(
cellsPerRow: 4,
superviewWidth: superviewWidth,
minimumInteritemSpacing: 0,
minimumLineSpacing: 0,
sectionInset: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
)
columnLayout = layout
collectionViewLayout = layout
}
}
ViewController.Swift
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var foos:[Foo] = []
var bars:[[Bar]] = [[]]
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.estimatedRowHeight = 188
tableView.rowHeight = UITableViewAutomaticDimension
for i in stride(from: 1, to: 10, by: 1) {
let foo = Foo()
foo.title = "Item (i)"
foo.description = "Description (i)"
foos.append(foo)
}
bars.removeAll()
for _ in 0 ..< foos.count {
bars.append(self.loadIconsSync())
}
}
func loadIconsSync() -> [Bar] {
var barObjects :[Bar] = []
let iconsCount = Utils.rnd(3, 8)
for _ in stride(from: 1, to: iconsCount, by: 1) {
barObjects.append(self.getRandomItem())
}
return barObjects
}
func getRandomItem() -> Bar {
let randomIndex = Utils.rnd(1, 10)
let bar = Bar()
bar.imageName = "icon_(randomIndex).png"
return bar
}
}
extension ViewController : UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let foo = foos[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FooTableViewCell
var bar = bars[indexPath.row]
cell.bars = bar
cell.titleLabel.text = foo.title
cell.descriptionLabel.text = foo.description
cell.delegateCollection = self
self.view.layoutIfNeeded()
cell.const_Height_CollectionView.constant = cell.iconsCollectionView.contentSize.height
self.view.layoutIfNeeded()
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return foos.count
}
}
extension ViewController : TableViewDelegate {
func cellTapped(for obj: FooTableViewCell) {
if let indexPath = tableView.indexPath(for: obj) {
bars[indexPath.row].append(getRandomItem())
self.tableView.beginUpdates()
self.tableView.reloadRows(at: [indexPath], with: .automatic)
self.tableView.endUpdates()
}
}
}
OUTPUT
EDIT / UPDATE 2
I was not aware about orientation supports and ipad support.
now when the orientation changes we have to re-layout the collection view.
So logic is
total items + 1 (+ 1 because of that plus icon )
Item Size * (total Items / 3).rounded
suppose you have 7 Items
so item size is 93 (Per row) * ( 8 / 3).rounded = 279
So here you need to manage some hardcoded values as per your requirement for iPad and Landscape mode. For now I am considering 3 objects per row same as iPhone design.
Here Hardcoded cell number is 3 You can manage your own.
Step1:
Add Following method in viewContorller.swift
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
self.tableView.beginUpdates()
self.tableView.reloadData()
self.tableView.endUpdates()
}
Replace cellForRowAtIndexPath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let foo = foos[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FooTableViewCell
cell.iconsCollectionView.initFlowLayout(superviewWidth: self.tableView.frame.width)
let bar = bars[indexPath.row]
cell.bars = bar
cell.titleLabel.text = foo.title
cell.descriptionLabel.text = foo.description
cell.delegateCollection = self
self.view.layoutIfNeeded()
let items:CGFloat = CGFloat(bar.count + 1)
let value = (items / 3.0).rounded(.awayFromZero)
cell.const_Height_CollectionView.constant = CGFloat((cell.iconsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize.height * value)
self.view.layoutIfNeeded()
cell.iconsCollectionView.setNeedsLayout()
return cell
}
And
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let footCell = cell as? FooTableViewCell {
footCell.const_Height_CollectionView.constant = footCell.iconsCollectionView.contentSize.height
self.view.layoutIfNeeded()
}
}
In TableviewCell
var bars:[Bar] = [] {
didSet {
self.iconsCollectionView.reloadData()
iconsCollectionView.setNeedsLayout()
self.layoutIfNeeded()
let items:CGFloat = CGFloat(bars.count + 1)
let value = (items / 3.0).rounded(.awayFromZero)
const_Height_CollectionView.constant = CGFloat((iconsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize.height * value)
self.layoutIfNeeded()
}
}
and
func cellTapped () {
iconsCollectionView.setNeedsLayout()
self.layoutIfNeeded()
self.setNeedsLayout()
let items:CGFloat = CGFloat(bars.count + 1)
let value = (items / 3.0).rounded(.awayFromZero)
const_Height_CollectionView.constant = CGFloat((iconsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize.height * value)
self.delegateCollection?.cellTapped(for: self)
}
这篇关于使用 UITableViewAutomaticDimension 制作带有嵌入式 UICollectionView 的 UITableView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!