简体   繁体   中英

UILabel not breaking lines in UITableViewCell

I'm building an app with a messenger like interface.
I use a tableView to accomplish this. Each cell contains a UIView - the message bubble and a UILabel - the message that is nested in the UIView .
It works great on texts of small sizes but for some reason when the UILabel is supposed to break lines it doesn't and it all is in one line. The amount of lines is set to zero.

This is my message handling class:

    func commonInit() {

    print(MessageView.frame.height)
    MessageView.clipsToBounds = true
    MessageView.layer.cornerRadius = 15
    myCellLabel.numberOfLines = 0
    let bubbleSize = CGSize(width: self.myCellLabel.frame.width + 28, height: self.myCellLabel.frame.height + 20)
    print(bubbleSize.height)
    MessageView.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: bubbleSize.width, height: bubbleSize.height)


    if reuseIdentifier! == "Request" {
        MessageView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMinXMaxYCorner]
        MessageView.backgroundColor = UIColor(red: 0, green: 122/255, blue: 1.0, alpha: 1.0)
    } else  {
        MessageView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner]
        MessageView.backgroundColor = UIColor.lightGray
    }


}

Cell calling function:

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    if queryCounter % 2 == 0 && indexPath.row % 2 == 0{
        cellReuseIdentifier = "Answer"

    } else {
        cellReuseIdentifier = "Request"
    }

    let cell:MessageCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MessageCell
    cell.myCellLabel.textColor = UIColor.white
    cell.myCellLabel.text = self.messages[indexPath.row]
    let height = cell.myCellLabel.text!.height(withConstrainedWidth: cell.myCellLabel.frame.width, font: cell.myCellLabel.font)
    print(height)
    cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1)

    return cell
}

The height variable is calculated based on text size. It shows that the text size is calculated normally - accounting for line break. I was unable to modify the cell height based on this calculation - nothing I tried works. I think it might be a constraints issue.
My Constraints: 在此处输入图片说明

在此处输入图片说明

How do I make the lines break? Please help.

EDIT: I just notice that the MessageView.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: bubbleSize.width, height: bubbleSize.height) has no affect what so ever on the message bubbles.

Setting the frame while using autolayout won't work.

I can't say what exactly happens here without the entire context, but some common pitfalls when reusing cells and autolayout are:

  1. Forgetting to set automatic height for your cells (expanding cell in a storyboard manually will override this setting)
  2. Tableview also needs estimatedHeight sometimes to work properly
  3. Sometimes you need to call setNeedsLayout after you add content to the cell

Check the console and if there are some warnings about breaking constraints, you can easily find issues there.

Try to find the label height based on label width and text font and then set your label height constraint to that.

extension String {
    func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)

        return ceil(boundingBox.height)
    }
}

something like this:

let textHeight = yourtext.height(withConstrainedWidth: yourlabel.frame.width, font: font)
yourLabel.heightAnchor.constraint(equalToConstant: textHeight).isActive = true

After multiple hours of trying everything I managed to fix it. The problem was with the constraints.
1. As you can see the in this old layout. The UIView was constrained everywhere except the left -> that's where the text goes. 在此处输入图片说明

  1. The commonInit() method of the UITableViewCell was called before any text was initialized. That's not good because all of the cell resizing is based on text which was not yet passed to the cell -> Move the method after cell initialization.

      let cell:MessageCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MessageCell cell.myCellLabel.text = self.messages[indexPath.row] //Before calling commonInit() we need to adjust the cell height. let height = cell.myCellLabel.text!.heightForView(text: cell.myCellLabel.text!, font: cell.myCellLabel.font, width: self.view.frame.width / 2) // Then we set the width of the UILabel for it to break lines at 26 characters if cell.myCellLabel.text!.count > 25 { tableView.rowHeight = height + 20 cell.myCellLabel.widthAnchor.constraint(equalToConstant: cell.frame.width / 2).isActive = true cell.updateConstraints() } // Calling commonInit() after adjustments cell.commonInit() cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1) return cell 
  2. Then we need to update the constraints so that the UIView and UILabel resize with the cell height. 在此处输入图片说明

在此处输入图片说明

  1. Done. Now it works as needed. Thank you for all of the suggestions! 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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