Почему collectionView-ячейка вдруг становится больше? - PullRequest
0 голосов
/ 23 мая 2019

Использование swift-5.0.1, iOS-12.2,

Я наблюдаю странное поведение на UICollectionView:

Внутри моего collectionView есть ячейки на весь экран, на которых показано изображение.

Мое наблюдение состоит в том, что всякий раз, когда изображение не может быть получено - в таком случае, вышеуказанная ячейка оказывается больше по размеру, чем ожидалось. Вопрос почему ??

Следующее изображение иллюстрирует проблему:

enter image description here

Любое изображение, которое нельзя получить, очевидно, не может быть отображено, и его ячейка получает backgroundColer, равный красному. Это все работает. Но почему одна ячейка, которая находится прямо над нулевой ячейкой, увеличилась в размерах ???

Все ячейки должны иметь размер, указанный желтыми прямоугольниками.

У меня есть два места в моем коде, где затрагивается высота ячейки:

  1. внутри инициализатора UICollectionViewCell:

mainImageView.heightAnchor.constraint(equalToConstant: 150)

  1. внутри UICollectionViewController sizeForItemAt:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return .init(width: view.frame.width, height: 150)
    }

Оба установлены на 150! Но в случае ошибки большая ячейка больше 150 - почему ??

Вот код более подробно:

import UIKit

class PhotoListCollectionViewCell: UICollectionViewCell {

    var mainImageView: UIImageView = {
        let imgV = UIImageView()
        imgV.contentMode = .scaleAspectFill
        return imgV
    }()
    var dateLabel = UILabel()
    var descriptionLabel = UILabel()
    var nameLabel = UILabel()
    var descContainerHeightConstraint = NSLayoutConstraint()
    var photoListCellViewModel : PhotoListCellViewModel? {
        didSet {
            nameLabel.text = photoListCellViewModel?.titleText
            descriptionLabel.text = photoListCellViewModel?.descText
            mainImageView.sd_setImage(with: URL( string: photoListCellViewModel?.imageUrl ?? "" ), completed: nil)
            dateLabel.text = photoListCellViewModel?.dateText
        }
    }

    func setConstraints() {

        addSubview(mainImageView)
        mainImageView.translatesAutoresizingMaskIntoConstraints = false
        mainImageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        mainImageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        mainImageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        mainImageView.heightAnchor.constraint(equalToConstant: 150)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = .red
        self.setConstraints()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
class CollectionViewController: BaseListController, UICollectionViewDelegateFlowLayout {

    fileprivate let cellId = "cellId"

    lazy var viewModel: PhotoListViewModel = {
        return PhotoListViewModel()
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        initView()
        initVM()
    }

    func initView() {
        self.navigationItem.title = "NavBar"
        collectionView.register(PhotoListCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
        collectionView.backgroundColor = .white
    }

    func initVM() { ... }

    func showAlert( _ message: String ) { ... }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return viewModel.numberOfCells
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as? PhotoListCollectionViewCell else {
            fatalError("Cell could not be dequeued")
        }
        let cellVM = viewModel.getCellViewModel( at: indexPath )
        cell.photoListCellViewModel = cellVM

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return .init(width: view.frame.width, height: 150)
    }
}

Приведенный ниже код, скорее всего, не имеет отношения к вопросу (но по причинам полноты ...)

class BaseListController: UICollectionViewController {

    init() {
        super.init(collectionViewLayout: UICollectionViewFlowLayout())
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Я также пытался изменить imgV.contentMode = .scaleAspectFill на imgV.contentMode = .scaleAspectFit. Но затем я теряю полную ширину изображений, как показано на иллюстрации здесь:

enter image description here

Но я думаю, что все ближе. Какая может быть идеальная настройка?

1 Ответ

1 голос
/ 23 мая 2019

Я наконец-то нашел решение.

С фантастической помощью Mykod я смог поиграть с contentMode imageView, отображаемым внутри collectionViewCell, а такжеего якорные ограничения.

Вот решение:

Внутри PhotoListCollectionViewCell, вы можете установить contentMode, а также clipsToBounce:

var mainImageView: UIImageView = {
    let imgV = UIImageView()
    imgV.contentMode = .scaleAspectFill
    imgV.clipsToBounds = true
    return imgV
}()

И что очень важно, вам нужно установить верхние, ведущие, конечные и нижние ограничения, равные верхним, ведущим, конечным и нижним ограничениям ячейки:


func setConstraints() {
    addSubview(mainImageView)
    mainImageView.translatesAutoresizingMaskIntoConstraints = false
    mainImageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
    mainImageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
    mainImageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
    mainImageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}

С учетом вышеуказанных изменений, imageView теперь заполняет весь экран и обрезается на правильную высоту - то есть все теперь правильно:)

enter image description here

...