编辑2-我能够通过使用在不同问题(https://stackoverflow.com/a/14413484/2584268)中找到的不同方法来使其工作,但是我还将其与GeneratorOfOne提供的代码结合在一起,并且我在下面发布了我的结果。但是,我仍然对此最终目标有疑问。目标是在每一行文本旁边都有行号,就像在代码编辑器中一样。问题是我需要保持连续的行数,因此,如果第一个单元格中有3行,则第二个单元格中的行号应从4开始,依此类推,但是我不相信我可以这样做因为正在计算单元格中的行数,所以我无法将值返回到tableview来设置第二个标签的文本(行号)...有什么想法吗?
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
}
我有一个自定义UITableViewCell子类,该子类正在使用自动调整大小的单元格。单元的大小是完美的,并且标签已正确扩展。但是,在运行时,我试图计算标签将扩展到的行数(我需要在标签旁边显示行号),但我无法实现这一点。我尝试了以下两种方法,但似乎都没有返回运行该应用程序时看到的正确行数:
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
}
因为它是一个自动调整大小的单元,我不能执行此操作吗?
编辑-这里是我正在使用的文本数组:
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.",
]
尝试使用NSAttributedString
:
func lineCountForLabel(label: UILabel) -> Int {
let font: UIFont = label.font
let attribtedString = label.attributedText.mutableCopy() as! NSMutableAttributedString
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = label.lineBreakMode
attribtedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: attribtedString.length))
let rect = attribtedString.boundingRectWithSize(CGSizeMake(label.frame.width, CGFloat(MAXFLOAT)),
options: .UsesLineFragmentOrigin | .UsesFontLeading,
context: nil)
return Int(ceil(rect.size.height/font.lineHeight))
}
更新:
您可以将字典的类型写为[Key:Value]的简写形式,因此您的这一行是不正确的:
let rect = string.boundingRectWithSize(xx, xx, xx, attributes: [font : NSFontAttributeName], context: nil)
更改:
[font : NSFontAttributeName]
至:
[NSFontAttributeName : font]
UPDATE(问题更新后)
您应该像这样在您的dataSource中存储一个行号:
class MyCell: UITableViewCell {
@IBOutlet var contentLabel: UILabel!
@IBOutlet private var numberLabel: UILabel!
}
class MasterViewController: UITableViewController {
var objects = [AnyObject]()
override func viewDidLoad() {
super.viewDidLoad()
let addButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "insertNewObject:")
self.navigationItem.rightBarButtonItem = addButton
self.tableView.estimatedRowHeight = 44
self.tableView.rowHeight = UITableViewAutomaticDimension
self.insertNewObject(self)
self.insertNewObject(self)
self.insertNewObject(self)
self.insertNewObject(self)
self.insertNewObject(self)
self.insertNewObject(self)
self.insertNewObject(self)
self.insertNewObject(self)
self.insertNewObject(self)
self.insertNewObject(self)
}
func insertNewObject(sender: AnyObject) {
var count = Int(arc4random_uniform(20)) + 1
var string = ""
while (count-- > 0) {
string += "This is a test."
}
objects.insert(["content" : string, "lineNumber" : 0], atIndex: 0)
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MyCell
var object = objects[indexPath.row] as! [String : AnyObject]
var startLineNumber = 0
if indexPath.row > 0 {
var pObject = objects[indexPath.row - 1] as! [String : AnyObject]
startLineNumber = pObject["lineNumber"] as! Int
}
cell.contentView.setNeedsLayout()
cell.contentView.layoutIfNeeded()
cell.contentLabel.text = object["content"] as? String
let lineNumber = lineCountForLabel(cell.contentLabel) + startLineNumber
cell.numberLabel.text = "\(lineNumber)"
object["lineNumber"] = lineNumber
objects[indexPath.row] = object
return cell
}
func lineCountForLabel(label: UILabel) -> Int {
let font: UIFont = label.font
let attribtedString = label.attributedText.mutableCopy() as! NSMutableAttributedString
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = label.lineBreakMode
attribtedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: attribtedString.length))
let rect = attribtedString.boundingRectWithSize(CGSizeMake(label.frame.width, CGFloat(MAXFLOAT)),
options: .UsesLineFragmentOrigin | .UsesFontLeading,
context: nil)
return Int(ceil(rect.size.height/font.lineHeight))
}
}
更新:
您的演示中有一些问题。
更改
lastNumUsed = 1
至
lastNumUsed = 0
并改变
for index in lastNumUsed+1...lastNumUsed+numLines
至
for index in lastNumUsed+1...lastNumUsed+numLines-1
最后,问题的关键在于gameInfo
的大小是否正确。当cellForRow
执行时,它的superview可能为零,因此单元格的大小和gameInfo
是不正确的。相反,您应该willDisplayCell
像这样计算行数:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: LineNumberSubtitleCell! = tableView.dequeueReusableCellWithIdentifier("GameCell", forIndexPath: indexPath) as! LineNumberSubtitleCell
if cell == nil {
cell = LineNumberSubtitleCell(style: UITableViewCellStyle.Default, reuseIdentifier: "GameCell")
}
cell.gameInfo.text = randomSizedTexts[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let cell = cell as! LineNumberSubtitleCell
cell.contentView.setNeedsLayout()
cell.contentView.layoutIfNeeded()
let numLines = getLinesArrayOfStringInLabel(cell.gameInfo)
cell.lineNumbers.text = "\(lastNumUsed)"
if !(lineNumbersList.count > indexPath.row) {
for index in lastNumUsed+1...lastNumUsed+numLines-1 {
cell.lineNumbers.text = cell.lineNumbers.text?.stringByAppendingString("\n\(index)")
if index == lastNumUsed+numLines-1 {
lastNumUsed = index+1
lineNumbersList.addObject(cell.lineNumbers.text!)
}
}
} else {
cell.lineNumbers.text = lineNumbersList.objectAtIndex(indexPath.row) as? String
}
}
调用该setNeedsLayout
方法将强制您的视图更新其布局。调用该layoutIfNeeded
方法将强制立即运行布局系统。因此,gameInfo
应重新计算的大小以更正。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句