即使这里有很多问题和答案,所以我不能创建UIScrollView
静态和动态内容(通过使用ContainerView
)并使尺寸正常工作。因此,我将提供一步一步的指导,直到我无法取得进展并且有人能够提供解决方案。通过这种方式,我们将有一个可行的样本,可以一步一步地完成工作。iOS:使用ContainerView的动态内容的UIScrollView(一步一步)
请注意:为方便起见,将所有步骤的输出上传到https://github.com/oysteinmyrmo/DynamicScrollablePage。测试Xcode项目可以从那里获取并进一步攻击。
更新:在@ agibson007的答案后,最后有几个步骤将原始步骤修复为工作解决方案。错误是指出错误,看到最后的步骤。
目标:
有各种静态UIView
S和长期滚动UIView
页面动态内容的ContainerView
。为了完整起见,动态内容将包含一些静态的UIView
和UITableView
,这些内容将扩展到其全部内容。最后一个因素似乎是我最近偶然发现的各种问题中重复出现的主题。
方法:
- 我们将开始一个新的Xcode项目(Xcode的8.2.1),并使用SWIFT 3.0.2作为语言。
- 我们将一步一步创建测试
UIView
S,UIViewController
S和其他所需物品。 - 在某些时候,我们有一个可以用来做内容的人谁能够动态扩展“模板”。
第1步:创建项目
开放的Xcode(8.2.1),开始一个新项目。
- 选择选项卡式应用程序。我们将在第一个选项卡中创建
UIScrollView
。 - 将产品名称设置为DynamicScrollablePage。
- 选择位置并创建项目。
步骤2:初步改变到Project
到UI的变化将在第一个选项卡来完成。该程序深受this answer影响,但我们将为我们的动态内容添加更多项目和ContainerView
。
Main.storyboard
,First View
(即标签1)删除这两个标签。- 单击
UIViewController
(首先命名)。转到其大小检查器,从Fixed
更改为Freeform
,并将高度更改为1500.这只是故事板中的视觉更改。 - 将其余的
UIView
重命名为RootView
。 - 在
RootView
的内部添加UIScrollView
。将其命名为ScrollView
。约束:- 滚动型 [顶,底,前置,宽度= RootView [顶,底,前置,宽度]。 根据我的经验,还必须设置宽度约束,以确保稍后覆盖整个屏幕。
- 添加
UIView
内ScrollView
并将其命名为ContentView
。约束:- 内容查看 [前置,顶部,底部,宽度= 滚动型 [前置,顶部,底部,宽度]。故事板现在会抱怨滚动高度。在下面的步骤后它不会投诉。
- 将项目添加到
ContentView
:- 加上一个
UIView
,将其命名为RedView
。设置RedView
[Leading,Trailing,Top] =ContentView
[Leading,Trailing,Top]。设置RedView
[高度,背景色] = [150,红色]。 - 在
RedView
下方添加一个UILabel
,将其名称/文本设置为FirstLabel
。设置FirstLabel
[Leading,Trailing] =ContentView
[Leading,Trailing]。设置FirstLabel
[Top] =RedView
[Bottom]。 - 在
FirstLabel
下面添加UIView
,将其命名为BlueView
。设置BlueView
[Leading,Trailing] =ContentView
[Leading,Trailing]。设置BlueView
[Top] =FirstLabel
[Bottom]。设置BlueView
[高度,背景色] = [450,蓝色]。 - 在
BlueView
下面添加一个UILabel
,将其名称/文本设置为SecondLabel
。设置SecondLabel
[Leading,Trailing] =ContentView
[Leading,Trailing]。设置SecondLabel
[Top] =BlueView
[Bottom]。 - 在
SecondLabel
的下方添加一个UIContainerView
,将其命名为ContainerView
。设置ContainerView
[Leading,Trailing] =ContentView
[Leading,Trailing]。设置ContainerView
[Top] =SecondLabel
[Bottom]。设置ContainerView
[内在尺寸] = [占位符](请参阅ContainerView
的尺寸检查员)。 将内部大小设置为占位符可以告诉Xcode它的大小是由其子视图定义的(据我所知)。错误,请参见最终步骤 - 在末尾添加一个
UILabel
,将其命名为BottomLabel
。设置BottomLabel
[Leading,Trailing] =ContentView
[Leading,Trailing]。设置为BottomView
[Top] =ContainerView
[Bottom]。 - 最后,控制+从
ScrollView
拖动到BottomView
并选择Bottom Space to ScrollView
。这将确保ScrollView
的高度是正确的。
- 加上一个
第3步:用动态内容
创建一个视图控制器现在,我们将创建用于显示动态内容的实际UIViewController
和xib
文件。我们将在xib
内部创建一个UITableView
,因此为简单起见,我们还需要一个带有简单标签的UITableViewCell
。
与内容创建一个文件雨燕,
TableViewCell.swift
:import UIKit class TableViewCell : UITableViewCell { }
创建
xib
/View
文件,命名为TableViewCell.xib
。执行以下操作:- 删除默认的
UIView
并将其替换为UITableViewCell
。 - 添加
UILabel
到该小区,将其命名为DataLabel
(这也将增加一个内容视图UIView
)。 - 将
UITableViewCell
的自定义类别设置为TableViewCell
。 - 将表格视图单元格标识符设置为
TableViewCellId
。 在双视模式,CTRL +标签拖动到
TableViewCell
类。结果应该是:import UIKit class TableViewCell : UITableViewCell { @IBOutlet weak var dataLabel: UILabel! }
- 删除默认的
与内容创建一个文件
DynamicEmbeddedViewController.swift
:import UIKit class DynamicEmbeddedViewController : UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var tableView: UITableView! let data = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Last"] override func viewDidLoad() { super.viewDidLoad() tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell") } func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell cell.dataLabel.text = data[indexPath.row] return cell } }
创建
xib
/View
文件,命名为DynamicEmbeddedView.xib
。重命名主UIView
到ContentView
和ContentView
中添加三个项目:- 添加
UIView
,将其命名GreenView
。设置GreenView
[Leading,Trailing,Top] =ContentView
[Leading,Trailing,Top]。设置GreenView
[高度] = [150]。 - 添加一个
UITableView
,将其命名为TableView
。设置TableView
[Leading,Trailing] =ContentView
[Leading,Trailing]。设置TableView
[Top] =GreenView
[Bottom]。 Set Intrinsic size =占位符。 我不确定这是否是正确的方法。 错误,请参见最终步骤 - 在
TableView
下面添加UIView
,将其命名为PurpleView
。设置PurpleView
[Leading,Trailing] =ContentView
[Leading,Trailing]。设置为PurpleView
[Top] =TableView
[Bottom]。 - 注:在这一点上,我们可能需要一些更多的约束在厦门国际银行,但我不确定是什么,以及如何,如果有的话。
- 设置
File's Owner
的自定义类来DynamicEmbeddedViewController
。 - 将
File's Owner
的查看出口设置为ContainerView
。 - 设置
TableView
的数据源和委托File's Owner
。 - 添加
TableView
的IBOutlet
到DynamicEmbeddedViewController
类。
- 添加
Connect在该
Main.storyboard
创建xib
和UIViewController
。- 将
ContainerView
的输出视图控制器的自定义类别设置为DynamicEmbeddedViewController
。 - 在
ContainerViews
输出视图控制器删除现有View
。 我不确定这是否真的需要。
- 将
现状的图片:
第4步:运行应用程序:
运行的应用程序,并滚动一路底部,包括反弹区,这是结果:
由此我们可以得出结论:
- 的
ContainerView
的位置是正确的(即在SecondLabel
和BottomLabel
之间),但BottomLabel
不遵守其约束低于ContainerView
。 - 的
TableView
的身高显然是0。这也可以,因为func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
看到不叫。如果我们在TableView
上设置高度限制,则项目将显示。 - 如果
ContainerView
的大小增加,ScrollView
的内容大小不会增加。 - 还希望在所有的时间显示在动态
TableView
所有项目和刚刚滚过他们,如果他们在ScrollView
只是静态数据。 - 这件事真的很混乱。
第5步:问题!
- 我们怎样才能使
ScrollView
的内容妥善包装的所有内容,包括TableView
生活在ContainerView
内的动态数据? - 约束设置是否正确?
- 我们应该在哪里以及如何计算适当的高度/内容尺寸?
- 这一切都是非常必要的;有没有更简单的方法来实现这一点?
第6步:修复@ agibson007的回答结束后的溶液:
添加
static let CELL_HEIGHT = 44
这样的:import UIKit class TableViewCell : UITableViewCell { @IBOutlet weak var dataLabel: UILabel! static let CELL_HEIGHT = 44 }
还原
TableView
的内在大小Default
从Placeholder
。- 在
TableView
上设置高度限制例如150。该值必须大于一个单元格的高度。 - 以
IBOutlet
的形式将高度限制添加到DynamicEmbeddedViewController
。 添加代码来计算并设置
TableView
高度限制。最后一类:import UIKit class DynamicEmbeddedViewController : UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var tableViewHeight: NSLayoutConstraint! let data = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Last"] override func viewDidLoad() { super.viewDidLoad() tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell") // Resize our constraint let totalHeight = data.count * TableViewCell.CELL_HEIGHT tableViewHeight.constant = CGFloat(totalHeight) self.updateViewConstraints() //in a real app a delegate call back would be good to update the constraint on the scrollview } func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell cell.dataLabel.text = data[indexPath.row] return cell } }
还原
ContainerView
的从Placeholder
固有大小Default
。- 在
ContainerView
上设置例如150的高度限制。该值将在代码中更新。 - 在
FirstViewController
中将高度限制作为IBOutlet
添加到ContainerView
。 - 在
FirstViewController
中添加ContainerView
作为IBOutlet
。 - 在
FirstViewController
中创建对DynamicEmbeddedViewController
的引用,以便它可以用于高度计算。 添加代码来计算并设置
ContainerView
高度限制。最终FirstViewController
类:import UIKit class FirstViewController: UIViewController { @IBOutlet weak var containerView: UIView! @IBOutlet weak var containerViewHeightConstraint: NSLayoutConstraint! var dynamicView: DynamicEmbeddedViewController? override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. if dynamicView != nil{ dynamicView?.tableView.reloadData() let size = dynamicView?.tableView.contentSize.height //cheating on the 300 because the other views in that controller at 150 each containerViewHeightConstraint.constant = size! + 300 self.view.updateConstraintsIfNeeded() } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if (segue.identifier == "ContainerViewSegue") { dynamicView = segue.destination as? DynamicEmbeddedViewController } }
}
最后按预期工作的一切!
请注意:所有的步骤的输出被上传到https://github.com/oysteinmyrmo/DynamicScrollablePage为了方便。测试Xcode项目可以从那里获取并进一步攻击。
我不得不说,在被这个问题困住了几个星期后,我有点期待解决方案如此简单。浮在互联网上的各种解决方案正在做各种不适合我的事情。所以这里是我要做的事情:1)将你的问题标记为答案,2)逐步更新你的步骤并更新git repo,3)开始并奖励你奖励你的时间来帮助我(和其他人)。我知道这不是在几分钟内完成的。无论如何,我打算做赏金,但你太快了! :-) –
让我知道你是否需要我在完成步骤后所做的一份副本。 – agibson007