具有动态子视图的自动布局
autolayout with dynamics subviews
我正尝试在我的 ios 10 应用程序上制作主屏幕,就像上面的照片一样。绿色视图实际上是滚动视图,我为其设置了约束以覆盖整个视图。我想让 scrollView 上的所有内容都可以滚动。黄色部分是带有原型单元格的 collection 视图。此视图中的项目数为 6。单元格由照片和标题组成。 Table 视图是新闻列表(照片+标题)。当在 table 视图中启动应用程序时,我加载了 10 条最新消息以及我通过 "load more" 机制获得的其余新闻。即使在横向上,我也需要适当的应用程序工作。我在定义此布局时遇到问题,因为 collection 视图和 table 视图具有动态高度,它们之间的 space 必须固定。通常在几乎所有教程中,人们只是修复了 scrollView 和 GridView,在这种情况下,应用程序在纵向方向上看起来不错,但我需要更大的灵活性。是否可以通过自动布局和约束来实现这一点,如果是的话,正确的方向是什么
更新:
内容视图
Collection 查看
我想要实现的是使 collection 在纵向视图中显示为两列和 3 行,在横向视图中显示为 3 列和 2 行。目前我有 collectionView 和滚动条,但我想一直扩展,因为 collectionView 的内容应该包含 6 个突出显示的新闻。
在 viewDidLoad 上,我尝试在正确的位置设置 table 视图(在 collection 视图之后):
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
collection.dataSource = self
collection.delegate = self
tableView.delegate = self
tableView.dataSource = self
self.view.addConstraint(
NSLayoutConstraint(
item: tableView,
attribute: .top,
relatedBy: .equal,
toItem: collection,
attribute: .bottom,
multiplier: 1.0,
constant: 20
))
tableView.frame = CGRect(x: 0,y: collection.collectionViewLayout.collectionViewContentSize.height,width: tableView.frame.width,height: tableView.frame.width ); // set new position exactly
downloadArticles(offset: "0") {}
}
我想要实现的一个例子是:
目前我有这个:
我想我是这样工作的:
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UITableViewDataSource, UICollectionViewDelegateFlowLayout, UITableViewDelegate {
@IBOutlet var collectionView: UICollectionView!
@IBOutlet var tableView: UITableView!
@IBOutlet var collectionViewHeightConstraint: NSLayoutConstraint!
@IBOutlet var tableViewHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "gridCell")
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "listCell")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// shrink wrap the collectionView and tableView to fit their content height snuggly
self.collectionViewHeightConstraint.constant = self.collectionView.contentSize.height
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - CollectionView Methods -
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
cell.backgroundColor = UIColor.lightGray
}
func calculateGridCellSize() -> CGSize {
// -----------------------------------------------------
// Calculate the size of the grid cells
// -----------------------------------------------------
let screenWidth = self.view.frame.size.width
let screenHeight = self.view.frame.size.height
var width:CGFloat = 0
var height:CGFloat = 0
if(UIDeviceOrientationIsPortrait(UIDevice.current.orientation)) {
width = screenWidth / 2.0 - 0.5
height = width
}
else {
width = screenWidth / 3.0 - 1.0
height = screenHeight / 2.0 - 0.5
}
let size:CGSize = CGSize(width: width, height: height)
return size
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return self.calculateGridCellSize()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (context) in
print("New screen size = \(size.width) x \(size.height)")
self.collectionView.collectionViewLayout.invalidateLayout()
self.collectionViewHeightConstraint.constant = self.collectionView.contentSize.height
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height
self.view.layoutIfNeeded()
}) { (context) in
self.collectionViewHeightConstraint.constant = self.collectionView.contentSize.height
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height
self.view.layoutIfNeeded()
}
}
// MARK: - TableView Methods -
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "listCell", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.textLabel?.text = "list cell \(indexPath.row)"
}
}
界面布局,我是这样做的:
- 将
scrollView
添加到主视图
- 固定
scrollview
所有四个面的主视图
- 将
contentView
添加到 scrollView
- 将
contentView
的所有四个边固定到 scrollView
- 使
contentView
宽度等于scrollView
宽度
- 将
collectionView
添加到 contentView
- 将
tableView
添加到 contentView
并垂直低于 collectionView
- 将
collectionView
的左侧、顶部、右侧固定到 contentView
- 将
tableView
的左侧、底部、右侧固定到 contentView
并将 tableView
的顶部固定到 collectionView
的底部
- 使
collectionView
高度为 667 并为 collectionView
高度创建 IBOutlet NSLayoutConstraint
(以便我们稍后更新)
- 使
tableView
高度为 667 并为 tableView
高度创建 IBOutlet NSLayoutConstraint
(稍后更新)
- 使
collectionView
最小项目间距 1 和行间距 1
- 为
collectionView
禁用 scrollingEnabled
- 为
tableView
禁用 scrollingEnabled
- 连接
collectionView
数据源并委托给控制器
- 连接
tableView
数据源并委托给控制器
如果有帮助的话,这里是布局的屏幕截图。
通常我使用纯代码构建 UI,您可以复制和粘贴,点击 运行 按钮,但由于您使用的是 Storyboard,所以我使用 Storyboard 展示了它,希望您能按照我的布局设置说明进行操作。
结果如下:
这是你想要的吗?
我正尝试在我的 ios 10 应用程序上制作主屏幕,就像上面的照片一样。绿色视图实际上是滚动视图,我为其设置了约束以覆盖整个视图。我想让 scrollView 上的所有内容都可以滚动。黄色部分是带有原型单元格的 collection 视图。此视图中的项目数为 6。单元格由照片和标题组成。 Table 视图是新闻列表(照片+标题)。当在 table 视图中启动应用程序时,我加载了 10 条最新消息以及我通过 "load more" 机制获得的其余新闻。即使在横向上,我也需要适当的应用程序工作。我在定义此布局时遇到问题,因为 collection 视图和 table 视图具有动态高度,它们之间的 space 必须固定。通常在几乎所有教程中,人们只是修复了 scrollView 和 GridView,在这种情况下,应用程序在纵向方向上看起来不错,但我需要更大的灵活性。是否可以通过自动布局和约束来实现这一点,如果是的话,正确的方向是什么
更新:
内容视图
Collection 查看
我想要实现的是使 collection 在纵向视图中显示为两列和 3 行,在横向视图中显示为 3 列和 2 行。目前我有 collectionView 和滚动条,但我想一直扩展,因为 collectionView 的内容应该包含 6 个突出显示的新闻。
在 viewDidLoad 上,我尝试在正确的位置设置 table 视图(在 collection 视图之后):
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
collection.dataSource = self
collection.delegate = self
tableView.delegate = self
tableView.dataSource = self
self.view.addConstraint(
NSLayoutConstraint(
item: tableView,
attribute: .top,
relatedBy: .equal,
toItem: collection,
attribute: .bottom,
multiplier: 1.0,
constant: 20
))
tableView.frame = CGRect(x: 0,y: collection.collectionViewLayout.collectionViewContentSize.height,width: tableView.frame.width,height: tableView.frame.width ); // set new position exactly
downloadArticles(offset: "0") {}
}
我想要实现的一个例子是:
目前我有这个:
我想我是这样工作的:
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UITableViewDataSource, UICollectionViewDelegateFlowLayout, UITableViewDelegate {
@IBOutlet var collectionView: UICollectionView!
@IBOutlet var tableView: UITableView!
@IBOutlet var collectionViewHeightConstraint: NSLayoutConstraint!
@IBOutlet var tableViewHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "gridCell")
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "listCell")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// shrink wrap the collectionView and tableView to fit their content height snuggly
self.collectionViewHeightConstraint.constant = self.collectionView.contentSize.height
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - CollectionView Methods -
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
cell.backgroundColor = UIColor.lightGray
}
func calculateGridCellSize() -> CGSize {
// -----------------------------------------------------
// Calculate the size of the grid cells
// -----------------------------------------------------
let screenWidth = self.view.frame.size.width
let screenHeight = self.view.frame.size.height
var width:CGFloat = 0
var height:CGFloat = 0
if(UIDeviceOrientationIsPortrait(UIDevice.current.orientation)) {
width = screenWidth / 2.0 - 0.5
height = width
}
else {
width = screenWidth / 3.0 - 1.0
height = screenHeight / 2.0 - 0.5
}
let size:CGSize = CGSize(width: width, height: height)
return size
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return self.calculateGridCellSize()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (context) in
print("New screen size = \(size.width) x \(size.height)")
self.collectionView.collectionViewLayout.invalidateLayout()
self.collectionViewHeightConstraint.constant = self.collectionView.contentSize.height
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height
self.view.layoutIfNeeded()
}) { (context) in
self.collectionViewHeightConstraint.constant = self.collectionView.contentSize.height
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height
self.view.layoutIfNeeded()
}
}
// MARK: - TableView Methods -
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "listCell", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.textLabel?.text = "list cell \(indexPath.row)"
}
}
界面布局,我是这样做的:
- 将
scrollView
添加到主视图 - 固定
scrollview
所有四个面的主视图 - 将
contentView
添加到scrollView
- 将
contentView
的所有四个边固定到scrollView
- 使
contentView
宽度等于scrollView
宽度 - 将
collectionView
添加到contentView
- 将
tableView
添加到contentView
并垂直低于collectionView
- 将
collectionView
的左侧、顶部、右侧固定到contentView
- 将
tableView
的左侧、底部、右侧固定到contentView
并将tableView
的顶部固定到collectionView
的底部
- 使
collectionView
高度为 667 并为collectionView
高度创建 IBOutletNSLayoutConstraint
(以便我们稍后更新) - 使
tableView
高度为 667 并为tableView
高度创建 IBOutletNSLayoutConstraint
(稍后更新) - 使
collectionView
最小项目间距 1 和行间距 1 - 为
collectionView
禁用 - 为
tableView
禁用 - 连接
collectionView
数据源并委托给控制器 - 连接
tableView
数据源并委托给控制器
scrollingEnabled
scrollingEnabled
如果有帮助的话,这里是布局的屏幕截图。
通常我使用纯代码构建 UI,您可以复制和粘贴,点击 运行 按钮,但由于您使用的是 Storyboard,所以我使用 Storyboard 展示了它,希望您能按照我的布局设置说明进行操作。
结果如下:
这是你想要的吗?