У меня есть этот пользовательский UIScrollView, который я ограничил супервизором, и он содержит UIView, называемый contentView, который я прикрепляю ко всем краям UIScrollView. Затем я добавляю UIView, который содержит 2 UIView и UICollectionView, в этот 'contentView', который находится в пользовательском классе UIScrollView. Отсюда я начинаю устанавливать ограничения как обычно. Все это делается программно.
2 UIViews отображаются правильно, а collectionView - нет. Это даже не показывает. Я устанавливаю ограничения collectionView для всех краев 'contentView'. Я не устанавливаю высоту, так как хочу, чтобы она основывалась на contentSize collectionView.
Вот пользовательский класс UIScrollView:
import UIKit
import PureLayout
class ContentScrollView: UIScrollView {
enum Direction {
case vertical
case horizontal
}
lazy var contentView: UIView = {
let view = UIView()
return view
}()
let direction: Direction
private var didSetupConstraints = false
// MARK: - Init
override init(frame: CGRect) {
self.direction = .vertical
super.init(frame: frame)
clipsToBounds = true
self.addSubview(contentView)
}
init(direction: Direction) {
self.direction = direction
super.init(frame: CGRect.zero)
clipsToBounds = true
translatesAutoresizingMaskIntoConstraints = false
self.addSubview(contentView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func updateConstraints() {
if !didSetupConstraints {
contentView.autoPinEdgesToSuperviewEdges()
switch direction {
case .vertical:
contentView.autoMatch(.width, to: .width, of: self)
contentView.autoSetDimension(ALDimension.height,
toSize: .leastNonzeroMagnitude,
relation: .greaterThanOrEqual)
break
case .horizontal:
contentView.autoMatch(.height, to: .height, of: self)
contentView.autoSetDimension(ALDimension.width,
toSize: .leastNonzeroMagnitude,
relation: .greaterThanOrEqual)
}
didSetupConstraints = true
}
super.updateConstraints()
}
}
Вот ограничения, которые у меня есть:
private func configureMainScrollView() {
scrollView.backgroundColor = .clear
scrollView.delegate = self
scrollView.alwaysBounceVertical = true
scrollView.contentInset = UIEdgeInsets(top: 78, left: 0, bottom: 0, right: 0)
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo: customSpacer.bottomAnchor).isActive = true
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: customAdContainerView.topAnchor).isActive = true
scrollView.contentView.addSubview(customContainerView)
configureCustomView()
scrollView.contentView.addSubview(collectionView)
configureCollectionView()
}
private func configureCustomizeButtonView() {
customContainerView.backgroundColor = .clear
customButton.setTitle("Customize", for: .normal)
customButton.backgroundColor = .clear
customButton.setTitleColor(UIColor.appColorSelectedTab(), for: .normal)
customButton.titleLabel?.tintColor = UIColor.appColorSelectedTab()
customButton.titleLabel?.font = UIFont.appFontButtonTitle()
customButton.contentHorizontalAlignment = .right;
divider.backgroundColor = UIColor.appColorDividerViewBackground()
customContainerView.translatesAutoresizingMaskIntoConstraints = false
customContainerView.topAnchor.constraint(equalTo: scrollView.contentView.topAnchor).isActive = true
customContainerView.leftAnchor.constraint(equalTo: scrollView.contentView.leftAnchor).isActive = true
customContainerView.rightAnchor.constraint(equalTo: scrollView.contentView.rightAnchor).isActive = true
customContainerView.addSubview(customButton)
customContainerView.addSubview(divider)
customButton.translatesAutoresizingMaskIntoConstraints = false
customButton.topAnchor.constraint(equalTo: customContainerView.topAnchor, constant: 13).isActive = true
customButton.rightAnchor.constraint(equalTo: customContainerView.rightAnchor, constant: -16).isActive = true
customButton.leftAnchor.constraint(equalTo: customContainerView.leftAnchor).isActive = true
customButton.heightAnchor.constraint(equalToConstant: 22).isActive = true
divider.translatesAutoresizingMaskIntoConstraints = false
divider.topAnchor.constraint(equalTo: customButton.bottomAnchor, constant: 16).isActive = true
divider.leftAnchor.constraint(equalTo: customContainerView.leftAnchor, constant: 16).isActive = true
divider.rightAnchor.constraint(equalTo: customContainerView.rightAnchor, constant: -16).isActive = true
divider.bottomAnchor.constraint(equalTo: customizeButtonContainerView.bottomAnchor).isActive = true
divider.heightAnchor.constraint(equalToConstant: 1).isActive = true
}
private func configureCollectionView() {
collectionView.backgroundColor = .clear
collectionView.delegate = self
collectionView.dataSource = self
collectionView.isScrollEnabled = false
collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: customCellId)
collectionView.register(CustomHeaderCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: customHeaderId)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.topAnchor.constraint(equalTo: customContainerView.bottomAnchor).isActive = true
collectionView.leftAnchor.constraint(equalTo: scrollView.contentView.leftAnchor).isActive = true
collectionView.rightAnchor.constraint(equalTo: scrollView.contentView.rightAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: scrollView.contentView.bottomAnchor).isActive = true
//collectionView.heightAnchor.constraint(equalToConstant: 750).isActive = true
}
Мне интересно, вызывает ли это как-то «contentView» в UIScrollView. Вы заметите закомментированный код, который устанавливает ограничение высоты для collectionView. Это единственный способ показать, но, очевидно, я ищу его, чтобы показать размер contentView для collectionView.
Любая помощь в этом будет оценена по достоинству. Спасибо!
Вероятно, для вас очевидно, в каком классе вы пишете configureMainScrollView и другие функции. То, что очевидно для вас, не очевидно для других.
Методы настройки находятся в моем контроллере представления. Я объявляю эти элементы пользовательского интерфейса в верхней части контроллера представления и устанавливаю ограничения в этих методах, которые вызываются в ViewDidLoad. @ЭльТомато





Для UICollectionView требуется ограничение по высоте (как и для любого UIScrollView).
Не путайте frame.height и contentSize.height.
Скажем, UIScrollView имеет высоту 200, а высота контента — 1000. Он знает, что ему нужно прокрутить, чтобы отобразить весь контент внутри этой высоты 200.
Если вы не установите frame.height на 200, независимо от того, что такое contentSize.height, он ничего не покажет.
То же самое относится и к этому случаю. UICollectionView требуется ограничение по высоте, даже если вы не хотите, чтобы он прокручивался.
То, что вы хотите здесь, это frame.height == contentSize.height.
Попробуйте следующее:
private var contentSizeObservation: NSKeyValueObservation?
let cvHeight = collectionView.heightAnchor.constraint(equalToConstant: 0)
cvHeight.isActive = true
contentSizeObservation = collectionView.observe(\.contentSize, options: .new, changeHandler: { (cv, _) in
cvHeight.constant = cv.collectionViewLayout.collectionViewContentSize.height
})
deinit звонке -deinit {
contentSizeObservation?.invalidate()
}
Этот подход гарантирует, что ваш collectionView всегда будет такой же большой по высоте, как и его содержимое.
Это помогло! Спасибо за объяснение, которое помогло мне понять проблему, а не просто дать ответ. Очень признателен. @Тарун
С этим подходом есть большая проблема — если это сделать после какого-то сетевого вызова на TAB A, в то время как мы все еще находимся на TAB B, contentSize считывается неправильно, случайная небольшая часть реального значения.
Откуда берутся вещи, которые вы называете customContainerView и collectionView?