I'm working on an app in swift. Currently, I'm working on the population of a table view with custom cells, see screenshot. However, right now I have the text set so that the title is exactly 2 lines and the summary is exactly 3 lines. By doing this, the text is sometimes truncated. Now, I want to set the priority for text in the title, so that if the title is truncated when it is 2 lines long I expand it to 3 lines and make the summary only 2 lines. I tried doing this with auto layout, but failed. Now I tried the following approach, according to this and this, but the function below also didn't seem to accurately determine if the text is truncated.
func isTruncated(label:UILabel) -> Bool {
let context = NSStringDrawingContext()
let text : NSAttributedString = NSAttributedString(string: label.text!, attributes: [NSFontAttributeName : label.font])
let labelSize : CGSize = CGSize(width: label.frame.width, height: CGFloat.max)
let options : NSStringDrawingOptions = unsafeBitCast(NSStringDrawingOptions.UsesLineFragmentOrigin.rawValue | NSStringDrawingOptions.UsesFontLeading.rawValue, NSStringDrawingOptions.self)
let labelRect : CGRect = text.boundingRectWithSize(labelSize, options: options, context: context)
if Float(labelRect.height/label.font.lineHeight) > Float(label.numberOfLines) {
return true
} else {
return false
}
}
Can anybody help? How can I change my function to make this work? Or should work with different auto layout constraints and how? Thanks so much!
EDIT: this is my current code. Some auto layout is done is the storyboard, however the changing auto layout is done in code. import UIKit
class FeedTableViewCell: UITableViewCell {
var thumbnailImage = UIImageView()
@IBOutlet var titleText: UILabel!
@IBOutlet var summaryText: UILabel!
@IBOutlet var sourceAndDateText: UILabel!
var imgTitleConst = NSLayoutConstraint()
var imgSummaryConst = NSLayoutConstraint()
var imgDetailConst = NSLayoutConstraint()
var titleConst = NSLayoutConstraint()
var summaryConst = NSLayoutConstraint()
var detailConst = NSLayoutConstraint()
var titleHeightConst = NSLayoutConstraint()
var summaryHeightConst = NSLayoutConstraint()
var imageRemoved = false
var titleConstAdd = false
override func awakeFromNib() {
super.awakeFromNib()
thumbnailImage.clipsToBounds = true
summaryText.clipsToBounds = true
titleText.clipsToBounds = true
sourceAndDateText.clipsToBounds = true
addImage()
}
func removeImage() {
if let viewToRemove = self.viewWithTag(123) {
imageRemoved = true
viewToRemove.removeFromSuperview()
self.contentView.removeConstraints([imgTitleConst, imgSummaryConst, imgDetailConst])
titleConst = NSLayoutConstraint(item: self.titleText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14)
summaryConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14)
detailConst = NSLayoutConstraint(item: sourceAndDateText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14)
self.contentView.addConstraints([titleConst, detailConst, summaryConst])
setNumberOfLines()
self.contentView.layoutSubviews()
}
}
func addImage() {
thumbnailImage.tag = 123
thumbnailImage.image = UIImage(named: "placeholder")
thumbnailImage.frame = CGRectMake(14, 12, 100, 100)
thumbnailImage.contentMode = UIViewContentMode.ScaleAspectFill
thumbnailImage.clipsToBounds = true
self.contentView.addSubview(thumbnailImage)
if imageRemoved {
self.contentView.removeConstraints([titleConst, summaryConst, detailConst])
}
var widthConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
var heightConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
var leftConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14)
var topConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 12)
imgTitleConst = NSLayoutConstraint(item: self.titleText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8)
imgSummaryConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8)
imgDetailConst = NSLayoutConstraint(item: sourceAndDateText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8)
self.contentView.addConstraints([widthConst, heightConst, leftConst, topConst, imgTitleConst, imgSummaryConst, imgDetailConst])
setNumberOfLines()
self.contentView.layoutSubviews()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setNumberOfLines() {
if titleConstAdd {
self.contentView.removeConstraints([titleHeightConst, summaryHeightConst])
}
if titleText.numberOfLines == 3 {
titleText.numberOfLines = 2
}
if countLabelLines(titleText) > 2 {
titleText.numberOfLines = 3
summaryText.numberOfLines = 2
println("adjusting label heigh to be taller")
titleHeightConst = NSLayoutConstraint(item: titleText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 51)
summaryHeightConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 32)
self.contentView.addConstraints([titleHeightConst, summaryHeightConst])
} else {
titleText.numberOfLines = 2
summaryText.numberOfLines = 3
titleHeightConst = NSLayoutConstraint(item: titleText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 36)
summaryHeightConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 47)
self.contentView.addConstraints([titleHeightConst, summaryHeightConst])
}
titleConstAdd = true
}
}
func countLabelLines(label:UILabel)->Int{
if let text = label.text{
// cast text to NSString so we can use sizeWithAttributes
var myText = text as NSString
//Set attributes
var attributes = [NSFontAttributeName : UIFont.boldSystemFontOfSize(14)]
//Calculate the size of your UILabel by using the systemfont and the paragraph we created before. Edit the font and replace it with yours if you use another
var labelSize = myText.boundingRectWithSize(CGSizeMake(label.bounds.width, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attributes, context: nil)
//Now we return the amount of lines using the ceil method
var lines = ceil(CGFloat(labelSize.height) / label.font.lineHeight)
println(labelSize.height)
println("\(lines)")
return Int(lines)
}
return 0
}