Создать динамический c collectionView внутри ячейки таблицы - PullRequest
4 голосов
/ 03 марта 2020

Я пытаюсь создать горизонтальное представление коллекции внутри ячеек таблицы с динамическим представлением размера uiimage c внутри, которое будет обязательным представлением.

Я создал UIView:

public class CardImage: UIView {

    private var imageView: UIImageView?
    private var titleLabel: UILabel?
    private var descriptionLabel: UILabel?
    private var subtitleLabel: UILabel?

    private var icon: UIImage?
    private var imageURL: String?

    private var screenPercentage: CGFloat = 1.0

    override public func layoutSubviews() {
        super.layoutSubviews()
        layer.cornerRadius = 4
    }

    public override func awakeFromNib() {
        super.awakeFromNib()
        setup()
        layoutSubviews()
    }

    public init() {
        super.init(frame: .zero)
        setup()
        layoutSubviews()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
        layoutSubviews()
    }

    public func fill(dto: SomeDTO) {
        setupImage(icon: dto.image, imageUrl: dto.imageURL)
        descriptionLabel?.text = dto.description
        titleLabel?.text = dto.title
        subtitleLabel?.text = dto.subtitle
        screenPercentage = dto.screenPercentage
    }

        private func setup() {
            isUserInteractionEnabled = true

            translatesAutoresizingMaskIntoConstraints = false

            backgroundColor = .red

            titleLabel = UILabel()
            titleLabel?.textColor = .white
            titleLabel?.numberOfLines = 1
            addSubview(titleLabel!)

            descriptionLabel = UILabel()
            descriptionLabel?.textColor = .white
            descriptionLabel?.numberOfLines = 2
            addSubview(descriptionLabel!)

            subtitleLabel = UILabel()
            subtitleLabel?.textColor = .white
            subtitleLabel?.numberOfLines = 1
            addSubview(subtitleLabel!)

            imageView = UIImageView(frame: .zero)
            imageView?.backgroundColor = .red
            addSubview(imageView!)

            setupConstraints()
        }

        private func setupImage(icon: UIImage?, imageUrl: String?) {
            if let url = imageURL {
                return
            }

            guard let image = icon else {
                return
            }

            imageView?.image = image
            imageView?.contentMode = .scaleAspectFit

            setNeedsDisplay()
            setNeedsLayout()
        }


        private func setupConstraints() {
            imageView?.translatesAutoresizingMaskIntoConstraints = false
            imageView?.topAnchor.constraint(equalTo: topAnchor).isActive = true
            imageView?.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
            imageView?.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true

            let screenSize = UIScreen.main.bounds
            let computedWidth = screenSize.width * screenPercentage
            imageView?.widthAnchor.constraint(equalToConstant: computedWidth).isActive = true
            //the image should be 16:9
            imageView?.heightAnchor.constraint(equalTo: widthAnchor, multiplier: 9.0/16.0).isActive = true

            titleLabel?.translatesAutoresizingMaskIntoConstraints = false
            titleLabel?.topAnchor.constraint(equalTo: imageView!.bottomAnchor, constant: 16).isActive = true
            titleLabel?.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16).isActive = true
            titleLabel?.heightAnchor.constraint(equalToConstant: 18).isActive = true

            subtitleLabel?.translatesAutoresizingMaskIntoConstraints = false
            subtitleLabel?.topAnchor.constraint(equalTo: titleLabel!.topAnchor).isActive = true
            subtitleLabel?.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16).isActive = true

            titleLabel?.widthAnchor.constraint(equalTo: subtitleLabel!.widthAnchor).isActive = true
            titleLabel?.trailingAnchor.constraint(equalTo: subtitleLabel!.leadingAnchor, constant: 6).isActive = true

            descriptionLabel?.translatesAutoresizingMaskIntoConstraints = false
            descriptionLabel?.topAnchor.constraint(equalTo: titleLabel!.bottomAnchor, constant: 16).isActive = true
            descriptionLabel?.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16).isActive = true
            descriptionLabel?.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16).isActive = true
            descriptionLabel?.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16).isActive = true
        }
}

Который будет внутри CollectionViewCell:

public class CardImageCollectionViewCell: UICollectionViewCell {
    private let view: CardImage = CardImage()

    override public func awakeFromNib() {
        super.awakeFromNib()

        translatesAutoresizingMaskIntoConstraints = false
//this only pin the view to the four anchors of the uicollectionview
        view.pinToBounds(of: self.contentView)
        backgroundColor = .clear

        AccessibilityManager.setup(self, log: true)
    }

    public func fill(dto: SomeDTO) {
        view.fill(dto: dto)
    }
}

А затем CollectionViewCell, внутри ячеек таблицы, который имеет вид коллекции:

public class CardImageCollectionView: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

        @IBOutlet private weak var collectionView: UICollectionView!
        private var dto: [SomeDTO] = []

        public override func awakeFromNib() {
            super.awakeFromNib()
            setup()
        }

        private func setup() {
            backgroundColor = .blue

            collectionView.backgroundColor = .clear
            collectionView.delegate = self
            collectionView.dataSource = self

            if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
                flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
            }

            registerCells()
        }

        func fill(dto: [SomaImageCardDTO]) {
            self.dto = dto
            DispatchQueue.main.async {
                self.collectionView.reloadData()
                self.collectionView.layoutIfNeeded()
            }
        }

        private func registerCells() {
            collectionView.register(UINib(nibName: String(describing: CardImageCollectionViewCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: CardImageCollectionViewCell.self))
        }

        public func numberOfSections(in collectionView: UICollectionView) -> Int {
            return 1
        }

        public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return dto.count
        }
        //this should not be setted since the sizing is automatic 
    //    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    //        return CGSize(width: 304, height: 238)
    //    }
    //
        public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: CardImageCollectionViewCell.self), for: indexPath) as! CardImageCollectionViewCell

            cell.fill(dto: dto[indexPath.row])
            return cell
        }
    }

две проблемы, с которыми я сталкиваюсь, это то, что изображение не может принимать любой размер, так как представление коллекции не имеет никакого размера, пока оно не заполнено некоторой информацией.

И затем, даже если я установлю размер изображения, я не может передать информацию в размер UITableViewcell.

1 Ответ

3 голосов
/ 01 апреля 2020

Если я правильно понимаю вашу проблему, у вас есть несколько строк в UITableView, которые имеют горизонтальные UICollectionViews. У этих представлений коллекции есть ячейки, которые имеют размер c в зависимости от изображений внутри них.

Таким образом, ширина UITableView фиксирована, но высота строки зависит от высоты UICollectionView, верно?

Я бы порекомендовал использовать саморазмерные ячейки в UITableView. См. Ссылку здесь: https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html

После этого вам нужно найти способ правильно рассчитать высоту UICollectionView, чтобы ячейка UITableView могла определить правильную высоту. Есть несколько способов сделать это, например, переопределив свойство intrinsicContentSize UICollectionView и вернув наибольшую высоту изображений.

...