在 UIStackView 中以编程方式堆叠视图
Stacking views programmatically in UIStackView
我花了很长时间尝试堆叠我以编程方式创建的视图。我查看了 中的示例,但没有用。下面列出的是代码,我从视图控制器调用 setUpListings
。有两个条目,但只显示一个条目。
import UIKit
import SnapKit
class ListingsView : UIView {
var containerView: UIView!
var listingsContainerView: UIStackView!
init() {
super.init(frame: CGRect.zero)
setUpContainerView()
setUpListingsContainer()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpContainerView() {
containerView = UIView()
self.addSubview(containerView)
containerView.snp.makeConstraints { (make) in
make.height.equalTo(self)
make.width.equalTo(self)
containerView.backgroundColor = UIColor.white
}
}
func setUpListingsContainer() {
listingsContainerView = UIStackView()
listingsContainerView.distribution = .equalSpacing
listingsContainerView.alignment = .fill
listingsContainerView.axis = .vertical
listingsContainerView.spacing = 10
listingsContainerView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(listingsContainerView)
listingsContainerView.snp.makeConstraints { (make) in
make.top.equalTo(containerView)
make.left.equalTo(containerView)
make.bottom.equalTo(containerView)
make.right.equalTo(containerView)
}
}
func setUpListings(listings: [Listing]) {
for listing in listings {
let listingEntry = ListingEntry(listingId: listing.id)
listingsContainerView.addArrangedSubview(listingEntry)
}
}
class ListingEntry : UIView {
var listingId: String?
var containerView: UIView!
init(listingId: String) {
super.init(frame: CGRect.zero)
self.listingId = listingId
self.setUpContainerView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpContainerView() {
containerView = UIView()
containerView.backgroundColor = UIColor.gray
self.addSubview(containerView)
containerView.snp.makeConstraints { (make) in
make.width.equalTo(150)
make.height.equalTo(150)
}
}
}
}
视图当前看起来像
但是积木应该堆叠起来。
两件事...
首先,我建议在使用 SnapKit 之类的东西之前学习约束和自动布局的工作原理。它 可以 使一些事情变得更容易 --- 但在对基本原理有很好的理解之前,不清楚什么在做什么。
其次,在开发过程中,它有助于为视图和子视图提供对比背景颜色。可以更轻松地查看帧在 运行 时间发生的情况。
所以,如果您要坚持使用 SnapKit...
尽量保留代码 "clean." 也就是说,不要在 snp.makeConstraints
块中放置任何不直接相关的内容(例如设置背景颜色)。
在您的 ListingEntry
class 中,您添加了一个子视图 (containerView
) 并将该视图的宽度和高度设置为 150,但您并未将其限制在其超级视图...导致视图高度为零。
看看我对你的代码所做的修改。我添加了应该使更改清晰的注释:
class MiscViewController: UIViewController {
var listingsView: ListingsView = {
let v = ListingsView()
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(listingsView)
listingsView.backgroundColor = .red
// constrain listingsView to all 4 sides with 40-pt "padding"
listingsView.snp.makeConstraints { (make) in
make.top.bottom.leading.trailing.equalToSuperview().inset(40.0)
}
let listings: [Listing] = [
Listing(id: "A"),
Listing(id: "B"),
Listing(id: "C"),
]
listingsView.setUpListings(listings: listings)
}
}
struct Listing {
var id: String = ""
}
class ListingsView : UIView {
var containerView: UIView!
var listingsContainerView: UIStackView!
init() {
super.init(frame: CGRect.zero)
// probably want to set clipsToBounds so any content doesn't extend outside the frame
clipsToBounds = true
setUpContainerView()
setUpListingsContainer()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpContainerView() {
containerView = UIView()
self.addSubview(containerView)
containerView.backgroundColor = UIColor.green
// constrain containerView to all 4 sides
containerView.snp.makeConstraints { (make) in
make.top.bottom.leading.trailing.equalToSuperview()
}
}
func setUpListingsContainer() {
listingsContainerView = UIStackView()
listingsContainerView.distribution = .equalSpacing
listingsContainerView.alignment = .fill
listingsContainerView.axis = .vertical
listingsContainerView.spacing = 10
containerView.addSubview(listingsContainerView)
// constrain listingsContainerView (a stack view) to all 4 sides
listingsContainerView.snp.makeConstraints { (make) in
make.top.leading.bottom.trailing.equalToSuperview()
}
}
func setUpListings(listings: [Listing]) {
for listing in listings {
let listingEntry = ListingEntry(listingId: listing.id)
listingEntry.backgroundColor = .cyan
listingsContainerView.addArrangedSubview(listingEntry)
}
}
class ListingEntry : UIView {
var listingId: String?
var containerView: UIView!
init(listingId: String) {
super.init(frame: CGRect.zero)
self.listingId = listingId
self.setUpContainerView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpContainerView() {
containerView = UIView()
containerView.backgroundColor = .gray
self.addSubview(containerView)
containerView.snp.makeConstraints { (make) in
// you want the "listing container" to be 150 x 150 pts
make.width.equalTo(150)
make.height.equalTo(150)
// and it needs top and bottom constraints to give self a height value
make.top.bottom.equalToSuperview()
// and it needs an x-position constraint
make.leading.equalToSuperview()
}
}
}
}
我已经将 "main" ListingsView
背景颜色设置为 red
...你看不到它,因为它的 containerView
子视图是 green
并填充视图。
每个 ListingEntry
视图都有 cyan
背景颜色,其 containerView
有 gray
背景颜色。
结果:
和调试视图层次结构:
最后的笔记...
- 您设置了 StackView
.distribution = .equalSpacing
,但您还设置了 .spacing = 10
,这没有意义。
- 如果您的
ListingEntry
视图多于垂直显示的视图,您将 运行 遇到问题。我希望你能把它放到滚动视图中。
我花了很长时间尝试堆叠我以编程方式创建的视图。我查看了 setUpListings
。有两个条目,但只显示一个条目。
import UIKit
import SnapKit
class ListingsView : UIView {
var containerView: UIView!
var listingsContainerView: UIStackView!
init() {
super.init(frame: CGRect.zero)
setUpContainerView()
setUpListingsContainer()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpContainerView() {
containerView = UIView()
self.addSubview(containerView)
containerView.snp.makeConstraints { (make) in
make.height.equalTo(self)
make.width.equalTo(self)
containerView.backgroundColor = UIColor.white
}
}
func setUpListingsContainer() {
listingsContainerView = UIStackView()
listingsContainerView.distribution = .equalSpacing
listingsContainerView.alignment = .fill
listingsContainerView.axis = .vertical
listingsContainerView.spacing = 10
listingsContainerView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(listingsContainerView)
listingsContainerView.snp.makeConstraints { (make) in
make.top.equalTo(containerView)
make.left.equalTo(containerView)
make.bottom.equalTo(containerView)
make.right.equalTo(containerView)
}
}
func setUpListings(listings: [Listing]) {
for listing in listings {
let listingEntry = ListingEntry(listingId: listing.id)
listingsContainerView.addArrangedSubview(listingEntry)
}
}
class ListingEntry : UIView {
var listingId: String?
var containerView: UIView!
init(listingId: String) {
super.init(frame: CGRect.zero)
self.listingId = listingId
self.setUpContainerView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpContainerView() {
containerView = UIView()
containerView.backgroundColor = UIColor.gray
self.addSubview(containerView)
containerView.snp.makeConstraints { (make) in
make.width.equalTo(150)
make.height.equalTo(150)
}
}
}
}
视图当前看起来像
但是积木应该堆叠起来。
两件事...
首先,我建议在使用 SnapKit 之类的东西之前学习约束和自动布局的工作原理。它 可以 使一些事情变得更容易 --- 但在对基本原理有很好的理解之前,不清楚什么在做什么。
其次,在开发过程中,它有助于为视图和子视图提供对比背景颜色。可以更轻松地查看帧在 运行 时间发生的情况。
所以,如果您要坚持使用 SnapKit...
尽量保留代码 "clean." 也就是说,不要在 snp.makeConstraints
块中放置任何不直接相关的内容(例如设置背景颜色)。
在您的 ListingEntry
class 中,您添加了一个子视图 (containerView
) 并将该视图的宽度和高度设置为 150,但您并未将其限制在其超级视图...导致视图高度为零。
看看我对你的代码所做的修改。我添加了应该使更改清晰的注释:
class MiscViewController: UIViewController {
var listingsView: ListingsView = {
let v = ListingsView()
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(listingsView)
listingsView.backgroundColor = .red
// constrain listingsView to all 4 sides with 40-pt "padding"
listingsView.snp.makeConstraints { (make) in
make.top.bottom.leading.trailing.equalToSuperview().inset(40.0)
}
let listings: [Listing] = [
Listing(id: "A"),
Listing(id: "B"),
Listing(id: "C"),
]
listingsView.setUpListings(listings: listings)
}
}
struct Listing {
var id: String = ""
}
class ListingsView : UIView {
var containerView: UIView!
var listingsContainerView: UIStackView!
init() {
super.init(frame: CGRect.zero)
// probably want to set clipsToBounds so any content doesn't extend outside the frame
clipsToBounds = true
setUpContainerView()
setUpListingsContainer()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpContainerView() {
containerView = UIView()
self.addSubview(containerView)
containerView.backgroundColor = UIColor.green
// constrain containerView to all 4 sides
containerView.snp.makeConstraints { (make) in
make.top.bottom.leading.trailing.equalToSuperview()
}
}
func setUpListingsContainer() {
listingsContainerView = UIStackView()
listingsContainerView.distribution = .equalSpacing
listingsContainerView.alignment = .fill
listingsContainerView.axis = .vertical
listingsContainerView.spacing = 10
containerView.addSubview(listingsContainerView)
// constrain listingsContainerView (a stack view) to all 4 sides
listingsContainerView.snp.makeConstraints { (make) in
make.top.leading.bottom.trailing.equalToSuperview()
}
}
func setUpListings(listings: [Listing]) {
for listing in listings {
let listingEntry = ListingEntry(listingId: listing.id)
listingEntry.backgroundColor = .cyan
listingsContainerView.addArrangedSubview(listingEntry)
}
}
class ListingEntry : UIView {
var listingId: String?
var containerView: UIView!
init(listingId: String) {
super.init(frame: CGRect.zero)
self.listingId = listingId
self.setUpContainerView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpContainerView() {
containerView = UIView()
containerView.backgroundColor = .gray
self.addSubview(containerView)
containerView.snp.makeConstraints { (make) in
// you want the "listing container" to be 150 x 150 pts
make.width.equalTo(150)
make.height.equalTo(150)
// and it needs top and bottom constraints to give self a height value
make.top.bottom.equalToSuperview()
// and it needs an x-position constraint
make.leading.equalToSuperview()
}
}
}
}
我已经将 "main" ListingsView
背景颜色设置为 red
...你看不到它,因为它的 containerView
子视图是 green
并填充视图。
每个 ListingEntry
视图都有 cyan
背景颜色,其 containerView
有 gray
背景颜色。
结果:
和调试视图层次结构:
最后的笔记...
- 您设置了 StackView
.distribution = .equalSpacing
,但您还设置了.spacing = 10
,这没有意义。 - 如果您的
ListingEntry
视图多于垂直显示的视图,您将 运行 遇到问题。我希望你能把它放到滚动视图中。