Martin Mickey
Martin Mickey

Reputation: 343

Swift - set height for UICollectionViewCell inside UITableViewCell

I have created UITableView with multiple sections. Each section has one line (UITableViewCell) and inside this line, I have UICollectionView and inside it UICollectionViewCell. Scrolling is working correctly. However, when I change the table row height, UICollectionView height remain unchaged. How to fix this?

class ViewController: UIViewController {

    var tab: HorizontalSelector? = nil

    @IBOutlet weak var tabView: UIView!

    override func viewDidLoad() {
       super.viewDidLoad()

       tab = HorizontalSelector(frame: self.tabView.frame)

       tab?.addSection("Jedna", withHeight: 100)
       tab?.addSection("Middle", withHeight: 100)
       tab?.addSection("Dva", withHeight: 100)

        self.tabView.addSubview(tab!)
    }
}

Class for horizontal selector

class HorizontalSelector: UITableView, UITableViewDataSource, UITableViewDelegate {

    let CELL_REUSE_ID = "cellSectionRow"
    let DEFAULT_ROW_HEIGHT: CGFloat = 44

    var sectionHeights: [CGFloat] =  []
    var sections: [String] = []

    init(frame: CGRect){

        var f: CGRect = frame
        f.origin.x = 0
        f.origin.y = 0

        super.init(frame: f, style: UITableViewStyle.plain)

        self.initialize()
    }

    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)

        self.initialize()
    }

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

    func initialize(){
        self.register(SectionCell.self, forCellReuseIdentifier: CELL_REUSE_ID)

        self.dataSource = self
        self.delegate = self

        self.backgroundColor = UIColor.blue
    }

    func addSection(_ section: String){
        sections.append(section)
        sectionHeights.append(DEFAULT_ROW_HEIGHT)
    }

    func addSection(_ section: String, withHeight: CGFloat){
        sections.append(section)
        sectionHeights.append(withHeight)
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return sectionHeights[indexPath.section]
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sections[section]
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let sectionCell = tableView.dequeueReusableCell(withIdentifier: CELL_REUSE_ID) as! SectionCell

        sectionCell.backgroundColor = UIColor.brown

        return sectionCell
    }
}

Class for single table section

class SectionCell: UITableViewCell {

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

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        self.initialize()
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        self.initialize()
    }

    func initialize(){

        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal

        self.contentView.addSubview(SectionCellRowCollection(frame: self.contentView.bounds, collectionViewLayout: layout))
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

Class for collection within single table section

class SectionCellRowCollection: UICollectionView, UICollectionViewDataSource, UICollectionViewDelegate {

    private let COLLECTION_CELL_ID = "collectionCell"

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

    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout){
        super.init(frame: frame, collectionViewLayout: layout)

        self.initialize()
    }

    private func initialize(){
        self.register(SectionCellRowCollectionCell.self, forCellWithReuseIdentifier: COLLECTION_CELL_ID)
        self.dataSource = self
        self.delegate = self

        self.backgroundColor = UIColor.yellow
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 12
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: COLLECTION_CELL_ID, for: indexPath as IndexPath) as! SectionCellRowCollectionCell

        cell.backgroundColor = UIColor.gray

        return cell

    }
}

Class for single cell inside colection

class SectionCellRowCollectionCell: UICollectionViewCell{

    var imageView: UIImageView!

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

    override init(frame: CGRect) {
        super.init(frame: frame)

        imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height*2/3))
        imageView.contentMode = UIViewContentMode.scaleAspectFit
        imageView.image = UIImage(named: "Swift-cover")
        contentView.addSubview(imageView)

        self.backgroundColor = UIColor.green
    }
}

Upvotes: 0

Views: 1324

Answers (2)

Maksym Musiienko
Maksym Musiienko

Reputation: 1248

Setup constraints for your collectionView and it will change its frame base on these constraints:

class SectionCell: UITableViewCell {
    private var collectionView: SectionCellRowCollection!

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

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        initialize()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        initialize()
    }

    private func initialize() {
        translatesAutoresizingMaskIntoConstraints = false
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        collectionView = SectionCellRowCollection(frame: contentView.bounds, collectionViewLayout: layout)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(collectionView)
        // constraints
        collectionView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
        collectionView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        collectionView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        collectionView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true

    }
}

Upvotes: 1

Optimus
Optimus

Reputation: 810

You have collectionView inside the tableviewCell so there is some static height of collectionView in storyboard so whatever the height of tableview the collectionView takes its height as its not clip to bounds.So to resolve that problem you must give height of tableView

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
    return 100.0;//Choose your custom row height
}

Then set the collectionView cell height that must be cell or equal to tableview height 

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    return CGSize(width: screenWidth, height:90 );
}

Upvotes: 1

Related Questions