UIScrollView не распознает размер содержимого UICollectionView

У меня есть этот пользовательский 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.

Любая помощь в этом будет оценена по достоинству. Спасибо!

Откуда берутся вещи, которые вы называете customContainerView и collectionView?

El Tomato 19.12.2020 03:07

Вероятно, для вас очевидно, в каком классе вы пишете configureMainScrollView и другие функции. То, что очевидно для вас, не очевидно для других.

El Tomato 19.12.2020 03:09

Методы настройки находятся в моем контроллере представления. Я объявляю эти элементы пользовательского интерфейса в верхней части контроллера представления и устанавливаю ограничения в этих методах, которые вызываются в ViewDidLoad. @ЭльТомато

SwiftCity 19.12.2020 04:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
438
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для UICollectionView требуется ограничение по высоте (как и для любого UIScrollView).

Не путайте frame.height и contentSize.height.

Скажем, UIScrollView имеет высоту 200, а высота контента — 1000. Он знает, что ему нужно прокрутить, чтобы отобразить весь контент внутри этой высоты 200.

Если вы не установите frame.height на 200, независимо от того, что такое contentSize.height, он ничего не покажет.

То же самое относится и к этому случаю. UICollectionView требуется ограничение по высоте, даже если вы не хотите, чтобы он прокручивался.

То, что вы хотите здесь, это frame.height == contentSize.height.

Попробуйте следующее:

  1. Объявите переменную внутри класса следующим образом.
private var contentSizeObservation: NSKeyValueObservation?
  1. Добавьте ограничение по высоте в collectionView и начните наблюдать за изменениями contentSize.
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
})
  1. НЕ забудьте убрать это в deinit звонке -
deinit {
    contentSizeObservation?.invalidate()
}

Этот подход гарантирует, что ваш collectionView всегда будет такой же большой по высоте, как и его содержимое.

Это помогло! Спасибо за объяснение, которое помогло мне понять проблему, а не просто дать ответ. Очень признателен. @Тарун

SwiftCity 19.12.2020 07:18

С этим подходом есть большая проблема — если это сделать после какого-то сетевого вызова на TAB A, в то время как мы все еще находимся на TAB B, contentSize считывается неправильно, случайная небольшая часть реального значения.

Starwave 23.01.2022 16:41

Другие вопросы по теме