0

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
    }
}
Martin Mickey
  • 333
  • 4
  • 13

2 Answers2

1

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 );
}
Optimus
  • 800
  • 5
  • 16
  • This will set collectionViewCell size, but collectionView itself is still not height enough. – Martin Mickey May 14 '17 at 15:05
  • For that you need to either set collectionView Height constraint then create outlet of that constraint and then set the collection height constraint to whatever value Or Set collectionView constraint like leading, trailing , top , bottom to UITableViewCell and then whatever height of UITableViewCell cell it auto takes height collectionView cell. let know if you have any confusion. Thanks – Optimus May 14 '17 at 15:18
  • Could you please provide a simple example for one constraint? I have for now used constraints only from Interface Builder. – Martin Mickey May 14 '17 at 15:26
  • Check below link http://stackoverflow.com/questions/22086054/unable-to-make-outlet-connection-to-a-constraint-in-ib – Optimus May 14 '17 at 15:28
  • I dont have constraints in IB, the whole "UI" is builded only from the code above – Martin Mickey May 14 '17 at 15:37
  • Then just set collectionView frame in tableview cell class awake from nib – Optimus May 14 '17 at 15:40
  • // create collectionview global in tableView cell class let SectionCellRowCollection = UICollectionView() //then add these lines to initialize func func initialize(){ let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal SectionCellRowCollection.frame = CGRect(x: 0, y: 0, width:320, height: 100) self.contentView.addSubview(SectionCellRowCollection, collectionViewLayout: layout)) } – Optimus May 14 '17 at 15:53
1

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

    }
}
Maksym Musiienko
  • 1,248
  • 8
  • 16