简体   繁体   English

在 tableview 单元格内创建动态 collectionView

[英]Create dynamic collectionView inside tableview cell

I'm trying to create a horizontal collection view inside a tableviewcell, with a dynamic size uiimageview inside, which will be the mandatory view.我正在尝试在 tableviewcell 内创建一个水平集合视图,里面有一个动态大小的 uiimageview,这将是强制视图。

I created a UIView :我创建了一个 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
        }
}

Which will be inside a CollectionViewCell:这将在 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)
    }
}

And then the CollectionViewCell, inside a tableviewcell, which has a collectionview:然后是 CollectionViewCell,在 tableviewcell 内,它有一个 collectionview:

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
        }
    }

The two problems I'm facing is, the image cannot assume any size, since the collection view doesn't have any size until it's filled with some info.我面临的两个问题是,图像不能假设任何大小,因为集合视图在填充一些信息之前没有任何大小。

And then, even if I set the image size, I cannot pass the info to the UITableViewcell size.然后,即使我设置了图像大小,也无法将信息传递给 UITableViewcell 大小。

If I understand your problem correctly, you have more than one rows in an UITableView which have horizontal UICollectionViews.如果我正确理解您的问题,那么您在 UITableView 中有不止一行具有水平 UICollectionViews。 Those collection views have cells which have dynamic size based on the images inside them.这些集合视图具有基于其中的图像具有动态大小的单元格。

So the width of the UITableView is fixed, but the height for the row depends on the height of the UICollectionView, correct?所以 UITableView 的宽度是固定的,但是行的高度取决于 UICollectionView 的高度,对吗?

I would recommend using self-sizing cells in the UITableView.我建议在 UITableView 中使用自动调整大小的单元格。 See the reference here: https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html请参阅此处的参考: https : //developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html

After that, you need to find a way to calculate the height of the UICollectionView correctly, so the UITableView cell can determine the correct height.之后需要想办法正确计算UICollectionView的高度,这样UITableView单元格才能确定正确的高度。 There are several ways to do it, for example by overriding the intrinsicContentSize property of the UICollectionView and returning the largest height of the images.有几种方法可以做到这一点,例如通过覆盖 UICollectionView 的intrinsicContentSize属性并返回图像的最大高度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM