EDIT 2-I was able to get it to work by using a different method found in a different question (https://stackoverflow.com/a/14413484/2584268), but I also combined it with the code provided by GeneratorOfOne, and I have posted my result below. I am still running into an issue with the end goal of this, though. The goal is to have line numbers next to each line of text, sort of like in a code editor. The problem is that I need to keep a running number of lines, so if there are 3 lines in the first cell, the line numbers in the second cell should start at 4 and so on, but I don't believe I can do this because the number of lines is being calculated in the cell so I cannot return a value back to the tableview to set the text of the second label (line numbers)...any ideas?
override func layoutSubviews() {
super.layoutSubviews()
calculateNumberOfLines()
}
var textDetail: String? {
didSet {
gameInfo.text = textDetail
}
}
func calculateNumberOfLines() {
let layoutManager = NSLayoutManager()
let textStorage = NSTextStorage(string: self.gameInfo!.text!)
textStorage.addAttribute(NSFontAttributeName, value: self.gameInfo!.font, range: NSMakeRange(0, textStorage.length))
let textContainer = NSTextContainer(size: CGSize(width:self.contentView.bounds.size.width - 56.0, height: CGFloat.max))
layoutManager.addTextContainer(textContainer)
layoutManager.textStorage = textStorage
if let text = gameInfo?.text {
let numberOfLines = getLinesArrayOfStringInLabel(gameInfo)
lineNumbers.text = "\(startingNum)"
for index in startingNum+1...startingNum+numberOfLines {
lineNumbers.text = lineNumbers.text?.stringByAppendingString("\n\(index)")
}
endingNum = startingNum+numberOfLines
//let numberOfLines = totalNumberOfLinesIn(text, currentGlyphIndex:0, currentLineNumber: 1, layoutManager: layoutManager, textContainer: textContainer)
//lineNumbers.text = "\(numberOfLines)"
} else { return }
}
func getLinesArrayOfStringInLabel(label: UILabel) -> Int {
var text = label.text as! NSString
var font = label.font
var rect = label.frame
var myFont = CTFontCreateWithName(font.fontName, font.pointSize, nil)
var attrString = NSMutableAttributedString(string: text as String)
attrString.addAttribute(String(kCTFontAttributeName), value: myFont, range: NSMakeRange(0, attrString.length))
let frameSetter = CTFramesetterCreateWithAttributedString(attrString)
var path = CGPathCreateMutable()
CGPathAddRect(path, nil, CGRectMake(0,0,rect.size.width,100000))
var frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil)
var lines = CTFrameGetLines(frame) as NSArray
var linesArray = NSMutableArray()
for line in lines as [AnyObject] {
var lineRef = line as! CTLineRef
var lineRange = CTLineGetStringRange(lineRef)
var range = NSMakeRange(lineRange.location, lineRange.length)
var lineString = text.substringWithRange(range)
linesArray.addObject(lineString)
}
return linesArray.count
}
I have a custom UITableViewCell subclass that is using self-sizing cells. The sizing of the cells is perfect and the label is being extended correctly. However, at run time I am trying to calculate the number of lines that the label will be extended to (I need to display the line numbers next to the label), and I am not able to achieve this. I have tried the following two methods and neither seem to be returning the correct number of lines that I am seeing when the app runs:
func lineCountForText(string: String, label: UILabel) -> Int {
let font: UIFont = UIFont(name: "SourceCodePro-Regular", size: label.font.pointSize)!
let rect = string.boundingRectWithSize(CGSizeMake(label.frame.width, CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [font : NSFontAttributeName], context: nil)
return Int(ceil(rect.size.height/font.lineHeight))
}
func numberOfLinesForString(string: String, size: CGSize, font: UIFont) -> Int {
let textStorage = NSTextStorage(string: string, attributes: [NSFontAttributeName: font])
let textContainer = NSTextContainer(size: size)
textContainer.lineBreakMode = .ByWordWrapping
textContainer.maximumNumberOfLines = 0
textContainer.lineFragmentPadding = 0
let layoutManager = NSLayoutManager()
layoutManager.textStorage = textStorage
layoutManager.addTextContainer(textContainer)
var numberOfLines = 0
var index = 0
var lineRange : NSRange = NSMakeRange(0, 0)
for (; index < layoutManager.numberOfGlyphs; numberOfLines++) {
layoutManager.lineFragmentRectForGlyphAtIndex(index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
}
return numberOfLines
}
Am I not able to do this because it is a self-sizing cell?
EDIT-Here is the array of text that I am using:
var randomSizedTexts = [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?",
"Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem",
", sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora",
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident",
"Et harum quidem rerum facilis est et expedita distinctio",
"Mauris id efficitur sapien. Nunc lobortis nisi ut ultricies scelerisque. Curabitur accumsan sit amet lacus in finibus. Aliquam dolor ante, rhoncus sit amet fermentum et, semper sit amet nisi. Proin pretium velit ut quam mollis fringilla. Nullam neque risus, vestibulum eget tortor sit amet, suscipit ultricies metus. In tortor ipsum, feugiat lacinia leo id, pulvinar lacinia velit. Suspendisse sit amet porta tellus, et scelerisque odio. Nam convallis sodales congue. Proin vel quam id arcu nisi non.",
]