以编程方式使用布局锚点的自动布局不起作用
Posted
技术标签:
【中文标题】以编程方式使用布局锚点的自动布局不起作用【英文标题】:Auto Layout using layout anchors programmatically not working 【发布时间】:2017-08-18 00:58:13 【问题描述】:我正在尝试添加一个堆栈视图,其中包含顶部的 UILabel 和下方的 UICollectionView。我试图通过将堆栈视图锚定到所有侧面来限制堆栈视图,使其占据整个视图。当我运行该应用程序时,会出现 UILabel 并出现集合视图的一部分。集合视图说它的宽度和高度都为零。任何帮助将不胜感激,谢谢。
var collectionView: UICollectionView!
var titleLabel: UILabel!
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.translatesAutoresizingMaskIntoConstraints = false
let margins = self.view.layoutMarginsGuide
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
layout.itemSize = CGSize(width: self.collectionView.frame.width / 4, height: self.collectionView.frame.width / 4)
layout.minimumInteritemSpacing = self.collectionView.frame.width / 15
layout.minimumLineSpacing = self.collectionView.frame.width / 5
collectionView.backgroundColor = UIColor.black
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
titleLabel = UILabel()
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.textAlignment = .center
titleLabel.numberOfLines = 1
titleLabel.font = UIFont.systemFont(ofSize: 22)
titleLabel.backgroundColor = UIColor.lightGray
titleLabel.text = "Challenges"
titleLabel.textColor = UIColor.red
let stackView = UIStackView(arrangedSubviews: [titleLabel, collectionView])
stackView.backgroundColor = UIColor.white
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.alignment = .fill
stackView.spacing = 5
self.view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
//stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
//stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1.0).isActive = true
更新:
我获取了我的代码并在一个新的单一视图应用程序中运行它,它按预期工作。因此,我认为值得一提的是,我正在尝试将其合并到精灵工具包游戏中,并通过这样做来展示视图控制器:
let root = self.view?.window?.rootViewController
var viewC = SelectionCollectionViewController()
root?.present(viewC, animated: false, completion: nil)
我需要采取什么特殊步骤,因为这是使用 sprite kit 完成的吗?
【问题讨论】:
一些事情,我认为这些都不重要。 (1) 尽可能不要使用框架。换句话说,将集合视图的框架设置为CGRect.zero
。同样,我不相信这有什么不同。 (2) 在viewDidLoad
中设置你的约束,但是——特别是如果你使用自动布局——不要在那里引用任何子视图框架。无论如何,您很可能会拥有CGRect.zero
。因此,请在 viewWillLayoutSubviews
中设置您的“布局”内容(我认为使用框架可能是正确的)。 (3) 如果您设置了其他 4 个约束,则无需设置 heightAnchor
。摆脱它。
最后一点(我的房间用完了)。在这三件事中,我打赌第二件事最有可能发挥作用。
我执行了代码,它显示了 UILabel - Spacing of 5 pts - CollectionView。预期的输出是什么?
预期输出是什么?
@dfd 感谢您的帮助!我将代码连同您的其他建议一起放入 ViewWillLayoutSubviews(),但似乎并没有解决问题。当我切换我的 collectionView 的框架而不是让我得到的 2 个红色矩形时它们消失了。
【参考方案1】:
我相信下面的屏幕截图是预期的输出。
您可能不需要 UIStackView ,您可以直接将其添加到 self.view 中。
添加到 self.view 后,您可以设置约束。您可以在 viewDidLayoutSubviews
中打印项目大小class ViewController: UIViewController
var collectionView: UICollectionView!
var titleLabel: UILabel!
let collectionCellIdentifier:String = "collectionCellId"
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.classForCoder(), forCellWithReuseIdentifier: collectionCellIdentifier)
collectionView.backgroundColor = UIColor.black
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
titleLabel = UILabel()
titleLabel.textAlignment = .center
titleLabel.numberOfLines = 1
titleLabel.font = UIFont.systemFont(ofSize: 22)
titleLabel.backgroundColor = UIColor.lightGray
titleLabel.text = "Challenges"
titleLabel.textColor = UIColor.red
titleLabel.translatesAutoresizingMaskIntoConstraints = false
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(titleLabel)
self.view.addSubview(collectionView)
setUpConstraints()
func setUpConstraints()
self.view.addConstraint(NSLayoutConstraint(item: self.titleLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier:0, constant:50.0 ))
titleLabel.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
titleLabel.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true
collectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
override func viewDidLayoutSubviews()
super.viewDidLayoutSubviews()
let flowLayout = (collectionView.collectionViewLayout as! UICollectionViewFlowLayout)
flowLayout.itemSize = CGSize(width: collectionView.frame.width / 4.0 , height: collectionView.frame.width / 4.0)
flowLayout.minimumInteritemSpacing = self.collectionView.frame.width / 15.0
flowLayout.minimumLineSpacing = self.collectionView.frame.width / 5.0
extension ViewController:UICollectionViewDataSource,UICollectionViewDelegate
func numberOfSections(in collectionView: UICollectionView) -> Int
return 1
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return 10
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionCellIdentifier, for: indexPath)
cell.backgroundColor = UIColor.gray
return cell
【讨论】:
【参考方案2】:我认为你需要知道这些函数中发生了什么:
viewDidLoad viewWillAppear viewWillLayoutSubviews viewDidLayoutSubviews viewDidAppear如果你使用autoLayout,在viewDidLoad()
时,框架没有被确认,因为在viewWillLayoutSubviews()
和viewDidLayoutSubviews()
时视图会自动调整,所以我建议你在viewDidAppear()
中编写这些代码,然后你可能会看到你想要的!
另外,如果你使用storyboard或者nib,你需要在awakeFromNib()
做这些
【讨论】:
感谢您的帮助!我将所有代码都放入 viewDidAppear() 中,但它仍然不起作用,还有其他建议吗? 永远不要将布局代码放在 viewDidAppear 中,除非你想看到视图在它们出现后移动!以上是关于以编程方式使用布局锚点的自动布局不起作用的主要内容,如果未能解决你的问题,请参考以下文章