在 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 背景颜色,其 containerViewgray 背景颜色。

结果:

和调试视图层次结构:

最后的笔记...

  • 您设置了 StackView .distribution = .equalSpacing,但您还设置了 .spacing = 10,这没有意义。
  • 如果您的 ListingEntry 视图多于垂直显示的视图,您将 运行 遇到问题。我希望你能把它放到滚动视图中。