Стекирование представлений программно в UIStackView

Я потратил много времени, пытаясь сложить представления, которые я создаю программно. Я просмотрел примеры из раздела Добавить представления в 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)
            }
        }
    }
}

В настоящее время представление выглядит как введите здесь описание изображения

Но блоки должны быть уложены друг на друга.


person AlwaysNull    schedule 26.01.2020    source источник
comment
похоже, что у вас проблемы с ограничениями. Зачем вы вообще добавили listingsContainerView конфигурацию в makeConstraints замыкание? В закрытии containerView.snp.makeConstraints вы даже не используете ввод make, а используете якоря. Это не правильно.   -  person Lew Winczynski    schedule 27.01.2020
comment
AlwaysNull --- просмотрите Как задать вопрос. Вы не описали и не показали, что вы пытаетесь сделать... Я посмотрел примеры... но это не сработало ничего нам не говорит. Опишите, что вы хотите получить... возможно, включите изображение вашей цели... покажите код, которому вы пытались следовать из примеров (НЕ то, что вы пробовали здесь с помощью SnapKit , так как это все очень и очень неправильно).   -  person DonMag    schedule 28.01.2020
comment
@DonMag Я обновил сообщение, пожалуйста, укажите, где я делаю это неправильно с SnapKit.   -  person AlwaysNull    schedule 29.01.2020


Ответы (1)


Пара вещей...

Во-первых, я бы посоветовал узнать, как работают ограничения и автомакет, прежде чем использовать что-то вроде SnapKit. Это может сделать некоторые вещи проще --- но до тех пор, пока вы не разберетесь в основах, неясно, что и к чему.

Во-вторых, во время разработки это помогает придать представлениям и подпредставлениям контрастные цвета фона. Значительно облегчает просмотр того, что происходит с кадрами во время выполнения.

Итак, если вы собираетесь придерживаться SnapKit...

Старайтесь содержать код в чистоте. То есть не помещайте в блок snp.makeConstraints ничего, что не связано напрямую (например, установка цветов фона).

В вашем классе ListingEntry вы добавляете подпредставление (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()
            }
        }
    }
}

Я установил «основной» цвет фона ListingsView на red ... вы его не видите, потому что его подвид containerView равен green и заполняет вид.

Каждое представление ListingEntry имеет цвет фона cyan, а его containerView имеет цвет фона gray.

Результат:

введите здесь описание изображения

и Иерархия представления отладки:

введите здесь описание изображения

Последние заметки...

  • Вы устанавливаете свой StackView .distribution = .equalSpacing, но также устанавливаете .spacing = 10, что не имеет смысла.
  • Если у вас больше ListingEntry просмотров, чем поместится по вертикали, вы столкнетесь с проблемами. Я ожидаю, что вы поместите это в представление прокрутки.
person DonMag    schedule 29.01.2020
comment
спасибо такой отличный ответ! Есть ли у вас какие-либо предложения о том, где я могу лучше понять макет и ограничения? - person AlwaysNull; 31.01.2020
comment
@AlwaysNull — существуют тысячи статей и руководств. Просто поищите, а потом читайте, читайте, читайте. Я бы начал с собственной документации Apple: developer.apple.com/ библиотека/архив/документация/ - person DonMag; 31.01.2020