Home > Back-end >  Table view inside a cell of table view, however its frame height is 0
Table view inside a cell of table view, however its frame height is 0

Time:03-11

I encountered with a problem when was trying to build a table view inside a cell of another table view. I thought it’s pretty straightforward task...

Structure of app:

  • Collection view with workout items.
  • After tapping on each, user will be moved to static table view, where problem’s occurred.

I noticed in Reveal app that table view appears in the cell and it doesn’t shout that constraints are not correct, everything seems fine. But table view has height of its frame 0.333.

Reveal app and the fact that table view exists

Reveal app screenshot and the fact that table view exists

But user would see this:

iPhone screenshot with wrong table view

I tried methods(with different values) as tough: estimatedHeightForRowAt, heightForRowAt, but they do nothing, by the way UITableView.automaticDimension returns -1. But when I set explicitly height for the row for outermost table view everything is good, except the fact that the size will be different in distinct elements, and table view is too big, or too small. I made this constraint, but it seems work only for one case when element has 3 splits:

self.heightAnchor.constraint(equalToConstant:  40   titleLabel.frame.height   CGFloat(splits.count) * 44.0)
With 3 splits in element Less than 3
enter image description here enter image description here

I read that adding subviews of custom cell to contentView instead of cell itself helped somebody, but in my case I got this message:

Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a table view cell's content view. We're considering the collapse unintentional and using standard height instead. Cell: <projectClimber.SplitCell: 0x140670050; baseClass = UITableViewCell; frame = (0 0; 355 44); autoresize = W; layer = <CALayer: 0x600003797700>>

I was able to dispose of this warning actually by removing contentView and just add sub view to cell itself. But it doesn’t solve anything.


I don’t really know how to set proper value to table view's height, maybe there’s an approach without using table view or maybe in different way. I want to hear your opinion about this, thank you.


Code

Main table view

class WorkoutStatisticsTableViewController: UITableViewController {
....

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //...
    //Switch statement and other cases 
    //...
    case 3:
    let cell = FourthTableViewCell()
cell.configure(with: workout)
cell.selectionStyle = .none 
// Here I added
    return cell
}
//I tried these methods, but nothing changed
//    override func tableView(_ tableView: UITableView, estimatedHeightForRowAt
indexPath: IndexPath) -> CGFloat {
//        return 250
//    }
//
//    override func tableView(_ tableView: UITableView, heightForRowAt indexPath:
IndexPath) -> CGFloat {
//
//        return UITableView.automaticDimension
//    }
....
}

Table view cell class, where lay title label and table view

class FourthTableViewCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
//...
//Methods for tableview delegate and data source and implementation of title label
//...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: SplitCell.reuseIdentifier, for: indexPath) as! SplitCell
cell.configure(cellWithNumber: indexPath.row   1, with: splits[indexPath.row])

cell.selectionStyle = .none
return cell
}
//Number of splits, i.e. rows in table view in this cell
var splits: [Int] = []

override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        self.tableView.dataSource = self
        self.tableView.delegate = self
        //just for making table view visible
        self.tableView.backgroundColor = .orange
        
            tableView.register(SplitCell.self, forCellReuseIdentifier: SplitCell.reuseIdentifier)
        
        addSubview(titleLabel)
        addSubview(tableView)
        
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        tableView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 20),
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
            titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
            
            
            tableView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10),
            tableView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
            tableView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10),
            tableView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
// Tried this line for calculating height of cell
//            self.heightAnchor.constraint(equalToConstant:  40   titleLabel.frame.height   CGFloat(splits.count) * 44.0)
        ])
    }
//Configure cell with workout element, which is used for taking splits
    func configure(with workout: Workout) {
        print("Configure func, workout's splits \(workout.splits.count)")
                //Need to populate splits this way, because in workout I use List<Int>
        for item in workout.splits {
            self.splits.append(item)
        }
   }
}

Split cell class. Where is located only two labels

class SplitCell: UITableViewCell {

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
    
    addSubview(titleLabel)
    addSubview(timeLabel)
    
    titleLabel.translatesAutoresizingMaskIntoConstraints = false
    timeLabel.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
        titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10),
        titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 15),
        titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
        
        timeLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10),
        timeLabel.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 50),
        timeLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10)
    ])
}

func configure(cellWithNumber number: Int, with time: Int) {
    titleLabel.text = "Split #\(number)"
    timeLabel.text = String.makeTimeString(seconds: time)
}
}

CodePudding user response:

After dozen of tries I decided to use this constraint for table view, that is located inside a cell of static table view:

tableView.heightAnchor.constraint(equalToConstant: CGFloat(splits.count) * 27)

But there's still a problem - magic value. 27 is a sum of 17, which is a height of label and 10 is a sum of constant of bottom and top constraints of label in an inner table view's cell.

I'm convinced there's a better solution somewhere, but for now it's better than nothing.

  • Related