0

Currently in my code, I'm programmatically adding a UITextView within a UITableViewCell and added the ability to auto-resize the cell based on how much content is typed by the user.

It currently looks like so:

override func viewDidLoad()
{
    tableView.estimatedRowHeight = 30.0
    tableView.rowHeight = UITableViewAutomaticDimension
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    // Dequeue the cell to load data
    let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

    if indexPath.section == 0
    {
        // Code
    }
    if indexPath.section == 1
    {            
        let textView: UITextView = UITextView()

        textView.delegate = self
        textView.textColor = UIColor.black
        textView.isScrollEnabled = false
        textView.translatesAutoresizingMaskIntoConstraints = false

        cell.addSubview(textView)

        let leadingConstraint = NSLayoutConstraint(item: cell.contentView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: textView, attribute: NSLayoutAttribute.leading, multiplier: 1.0, constant: 8.0)

        let trailingConstraint = NSLayoutConstraint(item: cell.contentView, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: textView, attribute: NSLayoutAttribute.trailing, multiplier: 1.0, constant: -8.0)

        cell.contentView.addConstraint(leadingConstraint)
        cell.contentView.addConstraint(trailingConstraint)

        let topConstraint = NSLayoutConstraint(item: cell.contentView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: textView, attribute: NSLayoutAttribute.top, multiplier: 1.0, constant: 0)

        let bottomConstraint = NSLayoutConstraint(item: cell.contentView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: textView, attribute: NSLayoutAttribute.bottom, multiplier: 1.0, constant: 0)

        cell.contentView.addConstraint(topConstraint)
        cell.contentView.addConstraint(bottomConstraint)
    }
    else if indexPath.section == 2
    {
        // Code
    }

    return cell
}

override func numberOfSections(in tableView: UITableView) -> Int
{
    return 3
}

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

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
    let headerCell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell")


    let titleLabel = headerCell?.viewWithTag(1) as! UILabel

    if section == 0
    {
        titleLabel.text = "Title"
    }
    else if section == 1
    {
        titleLabel.text = "Title"
    }
    else if section == 2
    {
        titleLabel.text = "Title"
    }

    return headerCell?.contentView
}

override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView?
{
    let footerCell = tableView.dequeueReusableCell(withIdentifier: "FooterCell")

    return footerCell
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
    if indexPath.section == 1
    {
        return UITableViewAutomaticDimension
    }

    return super.tableView(tableView, heightForRowAt: indexPath)
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
    return 35.0
}

override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
    return 15.0
}

func textViewDidChange(_ textView: UITextView)
{
    tableView.beginUpdates()
    tableView.endUpdates()
}

I only care about section 1 because that's the only cell that I want to auto-resize the cell's height. All other sections should maintain a static cell height.

The problem I have is that as soon as I press the enter key for the FIRST time in the UITextView to skip to the next line, I see very quickly some "ghost" cells and get a warning stating:

no index path for table cell being reused

The cell's height DOES dynamically re-size itself accordingly and after the initial return key is pressed, any subsequent new lines does not re-produce the "ghost" cells, but I still get the warnings.

What am I seem to be doing wrong?

Thanks

Pangu
  • 3,721
  • 11
  • 53
  • 120
  • Does the warning and ghost cells go away if you change the line `let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)` to not use an indexPath as follows - `let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell")`? – Fahim Mar 28 '17 at 06:09
  • @Fahim no effect – Pangu Mar 28 '17 at 06:16
  • @Pangu What actually you want in your output? – dahiya_boy Mar 28 '17 at 06:35
  • @pangu I think you have to set frame of your dynamic UITextview in heightForRowAtIndexPath method for indexPath.section 1 – Birendra Mar 28 '17 at 06:40

3 Answers3

0

TextView is inherited from scrollView and hence the content size of textView can be greater than frame (In which case textView will scroll). In order for tableView to calculate the automatic size for cell it needs components with implicit size like label or button. So in order for tableView to calculate implicit size for textView you should disable scroll.

textView.isScrollEnabled = false

Should allow your cell to expand :)

EDIT:

Looks like this happens when a reusable cell is used as section header (as in your case) Have a look at this : What is the meaning of the "no index path for table cell being reused" message in iOS 6/7?

Suggestion :

Create a normal xib add a view and return it as a section header else follow the answer posted in above link

Community
  • 1
  • 1
Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
0

Try this. Add this method too. func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat

Manisha
  • 181
  • 1
  • 6
  • There is no need to add that since OP already set the `estimatedRowHeight` in `viewDidLoad` – Rikh Mar 28 '17 at 06:31
0
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
 if(indexPath.row == 0){
  return heightForFirstRow
 }
return heightForStaticCell
}
anshul king
  • 558
  • 4
  • 17