0

I'm creating a bubble chat like application. I created custom functions for the receiving and sending bubble chats.

After creating them, I've added them into the cells that I've created using the UITableView.

However, I am not able to set the height of the cell, depending on the height of the custom cell itself.

For example, some text passed in could be longer than the one before.

Thus I can't seem to set each cell according to the custom bubble chat height.

Please help!

This are my tableview functions

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

// second
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return 100
}

// lastly created
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for:indexPath)

    if arrMsg[indexPath.row]["type"] as! String == "outgoing" {
        cell.contentView.addSubview(createOutGoingBubble(msg: arrMsg[indexPath.row]["message"] as! String))
    }
    if arrMsg[indexPath.row]["type"] as! String == "incoming" {
        cell.contentView.addSubview(createIncomingBubble(mymsg: arrMsg[indexPath.row]["message"] as! String))
    }
    return cell
}

This is how it looks currently

How do I set the height of the cell according to the custom bubble created inside the heightforrowat function?

Probably using the line to find the height and return it:

arrMsg[indexPath.row]["message"] as! String == "outgoing" 

**This is my function to create the custom bubble chats to be added into the tableviewcell

func createOutGoingBubble(msg:String) -> UIView {

    let subV = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))

    let label = UILabel()
    label.numberOfLines = 0
    label.font = UIFont.systemFont(ofSize: 18)
    label.textColor = .white
    label.text = msg

    let constraintRect = CGSize(width: 0.66 * view.frame.width,
                                height: .greatestFiniteMagnitude)
    let boundingBox = msg.boundingRect(with: constraintRect,
                                       options: .usesLineFragmentOrigin,
                                       attributes: [.font: label.font],
                                       context: nil)
    label.frame.size = CGSize(width: ceil(boundingBox.width),
                              height: ceil(boundingBox.height))

    let bubbleSize = CGSize(width: label.frame.width + 28,
                            height: label.frame.height + 20)

    let outgoingMessageView = UIImageView(frame:
        CGRect(x: view.frame.width - bubbleSize.width - 20,
               y: bubbleSize.height - 25,
               width: bubbleSize.width,
               height: bubbleSize.height))

    let bubbleImage = UIImage(named: "outgoing")?
        .resizableImage(withCapInsets: UIEdgeInsets(top: 17, left: 21, bottom: 17, right: 21),
                        resizingMode: .stretch)
        .withRenderingMode(UIImage.RenderingMode.alwaysTemplate)

    outgoingMessageView.image = bubbleImage
    outgoingMessageView.tintColor = UIColor(red: 0.40 , green: 0.71, blue: 1.00, alpha: 1)

    subV.addSubview(outgoingMessageView)

    label.center = outgoingMessageView.center

    subV.addSubview(label)

    return subV
}

Thanks in advance!

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • can you bring the code into the question? thanks in advance. – benc Nov 16 '18 at 03:08
  • done with the editing! the image of my simulator is there too. @benc – Iskandar Salleh Nov 16 '18 at 03:14
  • **Tip:** You should be adding views in the `cellForRowAt` method! You should be creating a custom cell class and having the bubble there and then adding just the text in `cellForRowAt`. Also, automatic dimension should take care of height if you have set up the constraints of the bubble relative to the `contentView` of the cell. – Rakesha Shastri Nov 16 '18 at 03:39
  • thanks @RakeshaShastri , but I am trying to only use one ViewController and populate everything in there. – Iskandar Salleh Nov 16 '18 at 03:41
  • 1
    @IskandarSalleh Unless you are using the default labels and image views in a `UITableViewCell`, you should be creating a custom table view cell everytime. _" I am trying to only use one ViewController and populate everything in there."_ Why? Also i am not asking you to create a new view controller. Just a custom `UITableViewCell`. You should look up some tutorial about table views. You do not seem familiar with how to use them. – Rakesha Shastri Nov 16 '18 at 03:43
  • @RakeshaShastri ive edited my question – Iskandar Salleh Nov 16 '18 at 03:47
  • Will you consider using constraints and have a dynamic cell height? You may want to take a look at this question: https://stackoverflow.com/questions/42717173/uitableviewcell-auto-height-based-on-amount-of-uilabel-text – Victor Kwok Nov 16 '18 at 04:18
  • thank you for the response @VictorKwok however that will not work as I'm using a custom subview and my cell is currently empty and has nothing inside it. is there any other way? – Iskandar Salleh Nov 16 '18 at 04:30
  • If you do not want to use constraints, you can try to make a function (maybe called heightForBubbleWithText) that calculates the height required for the cell in your custom cell subclass. Then in the cellForRowAt method, call this method with the text as parameter and return the height. – Victor Kwok Nov 16 '18 at 04:44
  • But actually even using a custom subview you may also use constraints to make a cell with dynamic height – Victor Kwok Nov 16 '18 at 04:45
  • @VictorKwok I have no idea how to do it as im still new to swift. is there any way where you could show? – Iskandar Salleh Nov 16 '18 at 04:51
  • and idea how I could use the -arrMsg[indexPath.row]["message"] as! String == "outgoing"- method to find the height and place it in the heightforrowat function? @VictorKwok – Iskandar Salleh Nov 16 '18 at 05:00
  • Take a look at this https://stackoverflow.com/questions/39268477/how-to-calculate-textview-height-base-on-text – Victor Kwok Nov 16 '18 at 05:33

3 Answers3

2

You can use Autolayout for the same and get free from all the coding part. Just set the constraint of the inner view in association with the cell and then right the following code.

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension

}

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

        let cell:ChatSenderTableViewCell = (tableView.dequeueReusableCell(withIdentifier: "ChatSenderTableViewCell", for: indexPath) as? ChatSenderTableViewCell)!

        cell.LabelChatMessage.text = "Your Message"
        cell.LabelChatMessage.numberOfLines = 0
        cell.LabelChatMessage.sizeToFit()

        return cell

}

I am using a custom cell name ChatSenderTableViewCell to create a bubble like effect containing a label for messages send or receive.

Devang Tandel
  • 2,988
  • 1
  • 21
  • 43
Nupur Gupta
  • 305
  • 1
  • 12
0

Use label inside of view and use margin from top and bottom according to your desire. Also, you need to make 0 number of lines in UIlabel. you can do it by using label.numberoflines = 0. Also, you need to add the following code to change the height of the row according to the text inside it.

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
Aqeel Ahmad
  • 709
  • 7
  • 20
0

You can try this:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    guard let cell = tableView.cellForRow(at: indexPath) else { return 0 }
    return cell.intrinsicContentSize.height
}

The intrinsicContentSize is the natural size for the receiving view, considering only properties of the view itself.

droberson
  • 43
  • 3