【问题标题】:Stacking views programmatically in UIStackView在 UIStackView 中以编程方式堆叠视图
【发布时间】:2020-05-12 08:17:23
【问题描述】:

我花了很长时间尝试堆叠我以编程方式创建的视图。我查看了来自Add views in UIStackView programmatically 的示例,但这没有用。下面列出的是代码,我从视图控制器调用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)
            }
        }
    }
}

视图当前看起来像

但是积木应该堆叠起来。

【问题讨论】:

  • 您的约束似乎有问题。你为什么还要将listingsContainerView 配置添加到makeConstraints 闭包中?在containerView.snp.makeConstraints 闭包中,您甚至不使用make 输入,而是使用锚点。这是错误的。
  • AlwaysNull --- 请查看How to Ask。你没有描述或展示你想要做什么......“我看了一些例子......但是没有用”并没有告诉我们任何事情。描述你想得到什么......也许包括你的目标的形象......显示你试图从示例中遵循的代码(NOT你在这里尝试使用 SnapKit ,因为这都是非常非常错误的)。
  • @DonMag 我更新了帖子,请指出我在使用 SnapKit 时做错了什么。

标签: swift uiview snapkit


【解决方案1】:

几件事...

首先,我建议使用 SnapKit 之类的工具之前了解约束和自动布局的工作原理。它可以让一些事情变得更容易 --- 但在对基本原理有很好的理解之前,不清楚什么在做什么。

其次,在开发过程中,它有助于为视图和子视图提供对比背景颜色。可以更轻松地查看运行时帧发生的情况。

所以,如果你要坚持使用 SnapKit...

尽量保持代码“干净”。也就是说,不要在 snp.makeConstraints 块中放入任何不直接相关的内容(例如设置背景颜色)。

在您的 ListingEntry 类中,您添加了一个子视图 (containerView) 并为该视图提供了 150 的宽度和高度,但您并未将其限制在其父视图中......这会导致视图高度零。

看看我对您的代码所做的修改。我添加了应该使更改清晰的 cmets:

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()
            }
        }
    }
}

我已将“主”ListingsView 背景颜色设置为red ...您看不到它,因为它的containerView 子视图是green 并填充了视图。

每个ListingEntry 视图都有一个cyan 背景颜色,它的containerView 有一个gray 背景颜色。

结果:

和调试视图层次结构:

最后的笔记...

  • 您设置了 StackView .distribution = .equalSpacing,但也设置了 .spacing = 10,这没有任何意义。
  • 如果您的ListingEntry 视图数量超过了垂直方向,您就会遇到问题。我希望您将其放入滚动视图中。

【讨论】:

  • 谢谢你这么好的回答!你有什么建议可以让我更好地理解布局和约束吗?
  • @AlwaysNull - 那里有成千上万的文章和教程。只需进行一些搜索,然后阅读,阅读,阅读。我将从 Apple 自己的文档开始:developer.apple.com/library/archive/documentation/…
猜你喜欢
  • 2015-08-24
  • 2017-10-09
  • 1970-01-01
  • 2016-07-27
  • 1970-01-01
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多