Cells with Dynamically created Heights overlap - ios

Hi im newer to IOS dev and Im more familiar with web dev. I am running into an issue where my cells are originally rendered how I would expect them to, but after scrolling to the bottom and scrolling back to the top of my screen I noticed that the cells begin to overlap each other. After reading other stack overflow posts I am starting to think that it has to do with how I create the cells. I am attempting to create multiple labels in a cell with a for loop similar to how someone would with PHP for web dev and im wondering if this is the proper way to do it/ is this a possible cause.
for i in 0...bars.count-1 {
var barLabelView:UIView = UIView()
var barLabel:UILabel = UILabel()
barLabelView.frame = CGRect(x: 20, y: CGFloat(20 + (70 * i)), width: barView.frame.width-40, height: 50)
barLabelView.backgroundColor = UIColor(displayP3Red: 27/255.0, green: 99/255.0, blue: 222/255.0, alpha: 1)
barLabelView.layer.cornerRadius = 10
barLabel.frame = CGRect(x: 0, y: 0, width: barLabelView.frame.width-10, height: 50)
barLabel.text = bars[i]
barLabel.textAlignment = .center
barLabel.numberOfLines = 0
barLabel.font = UIFont(name: "Chalkboard SE", size: 15)
barView.addSubview(barLabelView)
barLabelView.addSubview(barLabel)
}
Also heres how i set the height of the cell:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let crawlNameText = self.posts[indexPath.row].text
let size = CGSize(width: view.frame.width - 40, height: 1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let estimatedCrawlNameFrame = NSString(string: crawlNameText).boundingRect(with: size, options: options, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], context: nil)
let bars = posts[indexPath.row].bars.components(separatedBy: ", ")
let buds = posts[indexPath.row].buds.components(separatedBy: ", ")
if (self.posts[indexPath.row].type == "crawl") {
var cellHeightP1 = CGFloat(estimatedCrawlNameFrame.height + 110 + 20 + 20 + 20 + 40 + 60)
var cellHeightP2:CGFloat = CGFloat( 80 * bars.count)
var cellHeightP3:CGFloat = CGFloat( 80 * buds.count)
var cellHeight = cellHeightP1 + cellHeightP2 + cellHeightP3
return cellHeight
} else {
return estimatedCrawlNameFrame.width + 110 + 20
}
}
and here is my cellForRowAt function
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = nfTV.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! newsFeedCell
// Im guessing I would set the cell to nill here to clear the buttons I made
cell.setPost(post: posts[indexPath.row])
if (cell.profilePic != nil){
cell.profilePic.layer.cornerRadius = cell.profilePic.bounds.height / 2
cell.profilePic.clipsToBounds = true
}
cell.backgroundColor = UIColor.lightGray
print("made it here")
print(indexPath.row)
cell.frame = CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height)
return cell
}
I read that I might have to clear my cell before reusing it but im not sure how to set a cell to nil. I am also wondering if using a collection view would work better but I dont know the difference between that and a tableview.
Any help or suggestions is appreciated, thanks.

I answered my own question but I guess Ill leave this up in case it helps anyone in the future
I added the following lines of code at my comment in the cellForRowAt function to remove the buttons
for v in cell.barView.subviews{
v.removeFromSuperview()
}
for v in cell.budsView.subviews{
v.removeFromSuperview()
}
The issue was caused by some cells having more buttons than others so cells with less buttons were rendered with more buttons than necessary making it appear like it was overlap but in reality it was just recycled buttons.

Related

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:
Forgetting to set automatic height for your cells (expanding cell in a storyboard manually will override this setting)
Tableview also needs estimatedHeight sometimes to work properly
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.
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
Then we need to update the constraints so that the UIView and UILabel resize with the cell height.
Done. Now it works as needed. Thank you for all of the suggestions!

Some tableview cell content disappears after scroll (swift)

Below is my custom cell class:
class AthleteTableViewCell: UITableViewCell {
var myLabel1: UILabel!
var myLabel2: UILabel!
var profile: UIImageView!
var star = StarButton()
var touched = false
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:)")
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let gap : CGFloat = 10
let labelHeight: CGFloat = 30
let labelWidth: CGFloat = 150
let lineGap : CGFloat = 5
let label2Y : CGFloat = gap + labelHeight + lineGap
myLabel1 = UILabel()
myLabel1.frame = CGRect(x: gap, y: gap, width: labelWidth, height: labelHeight)
myLabel1.textColor = UIColor.black
contentView.addSubview(myLabel1)
myLabel2 = UILabel()
myLabel2.frame = CGRect(x: gap * 5, y: label2Y, width: labelHeight, height: labelHeight)
myLabel2.textColor = UIColor.white
myLabel2.textAlignment = .center
myLabel2.backgroundColor = UIColor.flatMint()
myLabel2.layer.cornerRadius = 15.0
myLabel2.clipsToBounds = true
contentView.addSubview(myLabel2)
profile = UIImageView()
profile.image = UIImage()
profile.frame = CGRect(x: bounds.width - gap, y: bounds.height / 2, width: bounds.height * 1.25, height: bounds.height * 1.25)
profile.layer.cornerRadius = (bounds.height * 1.25) / 2
profile.layer.masksToBounds = true
contentView.addSubview(profile)
if (touched != false) {
star.isSelected = true
star.frame = CGRect(x: gap, y: label2Y, width: labelHeight, height: labelHeight)
contentView.addSubview(star)
} else {
star.frame = CGRect(x: gap, y: label2Y, width: labelHeight, height: labelHeight)
contentView.addSubview(star)
star.isEnabled = true
}
}
}
and below is the method for creating my cells:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = AthleteTableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "myCell")
cell.myLabel1.text = "\(myArray[indexPath.row])"
cell.myLabel1.textColor = UIColor.white
cell.myLabel2.isHidden = true
cell.profile.image = UIImage(named: cell.myLabel1.text!)
cellArray.append(cell)
if (cell.touched) {
cell.star.isSelected = true
} else {
cell.star.isOpaque = true
}
cell.backgroundColor = UIColor(white: 1, alpha: 0.2)
return cell
}
and below is the method for selecting a cell which trips an animation that I would like the final state of to persist on the tableview cell.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
makeSelection(tableView, didSelectRowAt: indexPath)
}
func makeSelection(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! AthleteTableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.none
if(selectionArray.contains(myArray.object(at: indexPath.row))) {
//Popping selection off of the stack and updating all labels
updateLabels(tableView: tableView)
selectionArray.remove(myArray[indexPath.row])
cell.star.isFavorite = false
cell.myLabel2?.isHidden = true
//need to somehow implement all of the rank labels decreasing by one if I deselect someone
cell.touched = false
//updateLabels(tableView: tableView)
} else {
selectionArray.add(myArray[indexPath.row])
cell.touched = true
let rank = selectionArray.count
cell.myLabel2.isHidden = false
cell.myLabel2?.text = "\(rank)"
cell.star.isFavorite = true
}
}
This is a photo of what a cell looks like when you select it:
and this is a photo of that same cell after scrolling down so that is out of view and then scrolling back:
Something clearly goes very wrong here - I added that "touched" boolean to the custom table view cell class under the assumption that maybe the cells were being redrawn and there was no way for it to know whether it should have that star animated or not so it was considered nil but that fix doesn't seem to work (maybe I am onto something but implemented it incorrectly?)
Let me know if you have any clue what is going on here! thanks so much!!!
Your code has a variety of problems. In your tableView(_:cellForRowAt:) method, you should be calling dequeueReusableCell(withIdentifier:for:).
You should not be trying to read data from the cells in order to load content. You should save state data to a data model of some sort. An array works well for a table view with a single section, and an array of arrays works well for a sectioned table view.
There are countless tutorials on how to use table views. You need to go do some reading.
Mentioning it as an answer here as a step by step process
1) Create Struct for your data
struct Profile {
var personName: String?
var photoURL: String?
var rank: String?
var isTouched: Bool?
// add init method and stuff
}
2) Populate your array using these Profile elements. So that in the end you have an array of profiles.
3) Use this array to populate your tableview with each cell element getting data from the Profile object.
4) in your cellForRowAt method use dequeueReusableCell(withIdentifier:for:) to initialize your cell and assign values
5) if for that particular profile, isTouched is true then show
cell.star.isFavorite = true
else set it to false
6) in your didSelectRow, get indexpath.row and then in your array of profiles set Profile.isTouched=true/false based on your needs for that particular row and toggle accordingly. Update your profile array with new profile object.
7) refresh tableview.

Aligning multiple runtime generated UILabels in a UITableView

I have a UITableView that needs to support content by listing style something like
But the tricky part is that the amount of "Label" will vary with each cell, some may have only 4 but also up to 12. Also the "Value" can be either a single word or short phrase up to two lines(like in the image above). So I decided to use UIStackView to help me pack and size my UILabels used to display this. I am currently stuck at a problem when the "Label" varies in length like:
I need the leading end of the "Values" to be aligned like the first image even though the "Label" vary in length. Is there a behaviour of UIStackView that allows so? Or is there another approach that can allow me to obtain the results I need?
Note: Each "Label" and "Value" is in one UIStackView, I did it to align them.
I tried using String Formatting too, but "Values" with more than one line will wrap under the label instead of wrapping by itself like I manage to do in the images.
I tried placing all "Labels" in one UIStackView and all "Values" in another, I could no get them to align like they do in the images once the "Value" is more than one line.
Or if it might be a mistake I made somewhere, this is how I created the UIStackViews:
var higherCount = 0
if labels.count<values.count {
higherCount = values.count
} else {
higherCount = labels.count
}
mainStackView = UIStackView(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
for i in 0..<higherCount {
var height:CGFloat = 20
if (values[i] as NSString).size(attributes: [NSFontAttributeName:UIFont.systemFont(ofSize: UIFont.systemFontSize)]).width > frame.width {
height = 42
}
let stackViewToAdd = UIStackView(frame: CGRect(x: 0, y: 0, width: frame.width, height: height))
let label = UILabel(frame: CGRect(x: 0, y: 0, width: frame.width, height: height))
if labels.count<higherCount {
label.text = ""
} else {
label.text = labels[i]
}
label.setContentCompressionResistancePriority(1000, for: .horizontal)
label.setContentHuggingPriority(999, for: .horizontal)
stackViewToAdd.addArrangedSubview(label)
let value = UILabel(frame: CGRect(x: 0, y: 0, width: frame.width, height: height))
if values.count<higherCount {
value.text = ""
} else {
value.text = values[i]
}
value.lineBreakMode = .byWordWrapping
value.numberOfLines = 2
stackViewToAdd.addArrangedSubview(value)
mainStackView?.addArrangedSubview(stackViewToAdd)
}
mainStackView?.alignment = .fill
mainStackView?.axis = .vertical
mainStackView?.distribution = .fill
I you created your cell programmatically, then you can resize the cell programmatically depends on the size of UILabel Content.
In my case Label font is UIFont.systemFont(ofSize: 15), minimum TableViewCell height is 50, arrLabel1 and arrLabel2 will be the content of Labels.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrLable1.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "\(indexPath.row)")
let lable1 = UILabel(frame: CGRect(x: 10, y: 10, width: view.frame.size.width - 20, height: 0))
lable1.numberOfLines = 0
lable1.font = UIFont.systemFont(ofSize: 15)
lable1.text = arrLable1[indexPath.row]
lable1.sizeToFit()
cell.addSubview(lable1)
let lable2 = UILabel(frame: CGRect(x: 10, y: lable1.frame.origin.y + lable1.frame.size.height + 10 , width: view.frame.size.width - 20, height: 0))
lable2.numberOfLines = 0
lable2.font = UIFont.systemFont(ofSize: 15)
lable2.text = arrLable2[indexPath.row]
lable2.sizeToFit()
cell.addSubview(lable2)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath)
-> CGFloat {
let boundingRect1 = arrLable1[indexPath.row].boundingRect(with: CGSize(width: view.frame.size.width - 40 , height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin,attributes:[ NSFontAttributeName : UIFont.systemFont(ofSize: 15)] ,context: nil)
let boundingRect2 = arrLable2[indexPath.row].boundingRect(with: CGSize(width: view.frame.size.width - 40 , height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin,attributes:[ NSFontAttributeName : UIFont.systemFont(ofSize: 15)] ,context: nil)
guard boundingRect1.height + boundingRect2.height + 30 > 50 else {
return 50
}
return boundingRect1.height + boundingRect2.height + 30
}
Set Label numberOfLines to 0

Image and scrollView rendering making my tableview choppy

There may be no good solution for my problem, but I want to ask just in case.
I have a tableview in which each cell contains a horizontal scrollview of variable width. The width of each cell's scrollview depends on the number and sizes of the images for that cell. Everything works pretty well, but the tableview scrolls less smoothly than it could. I'm using Parse to retrieve the images (and pfquertableviewcontroller), but this question should apply to tableviews in general.
Here is my tableview code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
if var cell:MainFeedTableViewCell? = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier) as? MainFeedTableViewCell{
if(cell == nil) {
cell = NSBundle.mainBundle().loadNibNamed("MainFeedTableViewCell", owner: self, options: nil)[0] as? MainFeedTableViewCell
}
cell?.parseObject = object
return cell
}
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if let c = (cell as? MainFeedTableViewCell){
c.setUpObject()//this is where images are set
}
}
override func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if let c = (cell as? MainFeedTableViewCell){
c.resetObject() //this sets most of the properties to nil
}
}
And here is the function in my cell where images are set
func setUpObject(){
//I left out several lines of code where label text is set from the parseObject that is set when the cell is created
//setting images **problems here**
if let numImages = self.parseObject?["numImages"] as? Int{
self.newWidth1 = self.parseObject?["width1"] as? CGFloat
self.newWidth2 = self.parseObject?["width2"] as? CGFloat
self.newWidth3 = self.parseObject?["width3"] as? CGFloat
self.newWidth4 = self.parseObject?["width4"] as? CGFloat
self.newWidth5 = self.parseObject?["width5"] as? CGFloat
if numImages == 1{
self.containerView = UIView(frame: CGRect(x: self.scrollView.frame.minX, y: self.scrollView.bounds.minY - 90, width: self.scrollView.frame.width, height: self.scrollView.frame.height))
self.image1 = PFImageView(frame: CGRect(x: self.scrollView.frame.minX , y: self.scrollView.frame.minY, width: self.scrollView.frame.width, height: self.scrollView.frame.height))
self.image1?.contentMode = UIViewContentMode.ScaleAspectFit
self.image1!.file = self.parseObject?["image"] as? PFFile
self.image1!.loadInBackground()
self.containerView!.addSubview(self.image1!)
self.scrollView.contentSize = self.containerView!.bounds.size
self.scrollView.addSubview(self.containerView!)
}
else if numImages == 2{
if self.newWidth1 + self.newWidth2 < self.scrollView.frame.width{
self.containerView = UIView(frame: CGRect(x: self.scrollView.frame.midX - (self.newWidth1 + self.newWidth2)/2, y: self.scrollView.bounds.minY - 90, width: (self.newWidth1 + self.newWidth2), height: self.scrollView.frame.height))
}
else{
self.containerView = UIView(frame: CGRect(x: self.scrollView.frame.minX, y: self.scrollView.bounds.minY - 90, width: (self.newWidth1 + self.newWidth2), height: self.scrollView.frame.height))
}
self.image1 = PFImageView(frame: CGRect(x: self.scrollView.frame.minX , y: self.scrollView.frame.minY, width: self.newWidth1, height: self.scrollView.frame.height))
self.image1!.file = self.parseObject?["image"] as? PFFile
self.image1!.loadInBackground()
self.containerView!.addSubview(self.image1!)
self.image2 = PFImageView(frame: CGRect(x: (self.scrollView.frame.minX + self.newWidth1), y: self.scrollView.frame.minY, width: self.newWidth2, height: self.scrollView.frame.height))
self.image2!.file = self.parseObject?["image2"] as? PFFile
self.image2!.loadInBackground()
self.containerView!.addSubview(self.image2!)
self.subLayer = CALayer()
self.subLayer.backgroundColor = UIColor.whiteColor().CGColor
self.subLayer.frame = CGRect(x: self.newWidth1, y: self.scrollView.frame.minY, width: 1, height: self.scrollView.frame.height)
self.containerView!.layer.addSublayer(self.subLayer)
self.scrollView.contentSize = self.containerView!.bounds.size
self.scrollView.addSubview(self.containerView!)
}
//repeat similar code for cases where there are 3, 4, or 5 images
There might be a fundamental issue with dynamically adjusting the size of the scrollview and adding it to superview just in time, but I'm trying to follow the design mockup that my designer gave me.
Here is what the scrollview on the cell looks like (with each image in the scrollview separated by a thin white line)
Remove your willDisplayCell and didEndDisplayingCell. That will fire as you scroll and your setUpObject code, while not huge, will block the main thread slightly. Instead move setUpObject() to right before returning the cell in cellForRowAtIndexPath.
Depending on how many rows you have and performance requirements you could also adjust the viewController to download all of the images ahead of time and pass them to the cell instead of loading them inside the cell.

Custom tableview Cell position is wrong

I want to implement the chat bubble for my app,everything goes fine except the positioning of those cells. I wonder if there is a way to haddle this, this is so awkward to have a screen like this
(I have only 1 section and 2 rows in this tableview)
Thx for attence the cells look like this
http://imgur.com/9F6JH39
The 2nd line should be in the second cell but it appers in the 3rd one and i dont know why
These are the code for my custom view for my custom class:
class DialogCell: UITableViewCell {
#IBOutlet var iconImageView: UIImageView!
#IBOutlet var messageBackgroundView: UIImageView!
#IBOutlet var messageContentTextView: UITextView!
var maximumSize:CGSize = CGSize(width: 150, height: 1000)
var padding:CGFloat = 10
var exactSize:CGSize = CGSize(width: 0, height: 0)
let magicNumber:CGFloat = 50
func setViews(icon:UIImage,messageContent:String,backgroungImage:UIImage){
iconImageView = UIImageView()
messageContentTextView = UITextView()
messageBackgroundView = UIImageView()
iconImageView.layer.cornerRadius = magicNumber / 8
iconImageView.layer.masksToBounds = true
let orginX = self.frame.origin.x
let orginY = self.frame.origin.y
self.iconImageView.frame.origin.x = orginX + padding
self.iconImageView.frame.origin.y = orginY + padding
self.iconImageView.image = icon
self.iconImageView.frame.size = CGSize(width: magicNumber, height: magicNumber)
messageContentTextView.text = messageContent
exactSize = messageContentTextView.sizeThatFits(maximumSize)
self.messageContentTextView.frame = CGRect(origin: CGPoint(x: orginX + 3 * padding + magicNumber, y: orginY + padding),
size: exactSize)
self.messageContentTextView.allowsEditingTextAttributes = false
// self.messageContentTextView.
self.messageContentTextView.backgroundColor = UIColor.clearColor()
// exactSize.height
exactSize.width += 1.5 * padding
exactSize.height += 0.5 * padding
var new_image = backgroungImage.resizableImageWithCapInsets(UIEdgeInsets(top: 15, left: 10, bottom: 5, right: 5), resizingMode: UIImageResizingMode.Tile)
messageBackgroundView.image = new_image
self.messageBackgroundView.frame = CGRect(origin: CGPoint(x: orginX + 2 * padding + magicNumber, y: orginY + padding),
size: exactSize)
self.layer.opacity = 0.3
self.addSubview(iconImageView)
self.addSubview(messageBackgroundView)
self.addSubview(messageContentTextView)
}
![}][2]
And the main method in my tableView Controller
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as DialogCell
// dialogues[indexPath.row % dialogues.count]
var str:String = "\(indexPath.row) Line"
for _ in 0...2 {
str += str
}
cell.textLabel?.text = "\(indexPath.row) Line"
cell.setViews(UIImage(named: "minion")!, messageContent: str, backgroungImage: UIImage(named: "dialogue")!)
return cell}
I don't know the exact answer but I can advise a different way which I did.
You can add an UIScrollView to your controller and every time when a message received add it to your scrollView dynamically and change the contentSize of scroll.Also you need to control your label positions every time. This can be another way but it's not your answer.

Resources