我有一个UILabel
,在某些情况下,文本比UILabel
本身还要长,所以我将文本看作"bla bla bla..."
,我想在UILabel
的末尾添加一个...Read More
按钮文本。
我读过一些帖子,但他们提供的解决方案对我来说并不好,例如:计算有多少个字符将进入UILabel
,但我使用的字体每个字符都有不同的宽度。
我怎样才能做到这一点?
提前感谢!
发布于 2019-03-22 11:22:27
这适用于Swift 5
这里是@ramchandran答案的一个更安全的版本,因为您不知道用户将输入多少个字符。
在他的回答中,如果用户输入的字符串长度小于您决定用于... Readmore
的任何文本的长度,那么它将崩溃。例如,这就是你使用它的方式
if yourLabel.text!.count > 1 {
let readmoreFont = UIFont(name: "Helvetica-Oblique", size: 11.0)
let readmoreFontColor = UIColor.blue
DispatchQueue.main.async {
self.yourLabel.addTrailing(with: "... ", moreText: "Readmore", moreTextFont: readmoreFont!, moreTextColor: readmoreFontColor)
}
}
在上面的例子中,... Readmore
的输出总共是12个字符。如果用户输入的字符串是yourLabel.text = "12345678"
,那么字符串的文本将只有8个字符。它会崩溃,因为在下面一行中使用((trimmedString?.count ?? 0) - readMoreLength)
的范围将产生负结果:
// “12345678” minus “... Readmore” = negative four (8 - 12 = -4)
let trimmedForReadMore: String = (trimmedString! as NSString).replacingCharacters(in: NSRange(location: ((trimmedString?.count ?? 0) - readMoreLength), length: readMoreLength), with: "") + trailingText
我添加了一个安全检查,以确保如果输入的字符串少于或等于您决定用作... Readmore
的任何字符串的字符数,它将返回,并且将导致崩溃的行永远不会到达:
// trimmedString is the string the user entered
guard let safeTrimmedString = trimmedString else { return }
if safeTrimmedString.count <= readMoreLength { return }
它位于addTrailing
函数的中心
extension UILabel{
func addTrailing(with trailingText: String, moreText: String, moreTextFont: UIFont, moreTextColor: UIColor) {
let readMoreText: String = trailingText + moreText
if self.visibleTextLength == 0 { return }
let lengthForVisibleString: Int = self.visibleTextLength
if let myText = self.text {
let mutableString: String = myText
let trimmedString: String? = (mutableString as NSString).replacingCharacters(in: NSRange(location: lengthForVisibleString, length: myText.count - lengthForVisibleString), with: "")
let readMoreLength: Int = (readMoreText.count)
guard let safeTrimmedString = trimmedString else { return }
if safeTrimmedString.count <= readMoreLength { return }
print("this number \(safeTrimmedString.count) should never be less\n")
print("then this number \(readMoreLength)")
// "safeTrimmedString.count - readMoreLength" should never be less then the readMoreLength because it'll be a negative value and will crash
let trimmedForReadMore: String = (safeTrimmedString as NSString).replacingCharacters(in: NSRange(location: safeTrimmedString.count - readMoreLength, length: readMoreLength), with: "") + trailingText
let answerAttributed = NSMutableAttributedString(string: trimmedForReadMore, attributes: [NSAttributedString.Key.font: self.font])
let readMoreAttributed = NSMutableAttributedString(string: moreText, attributes: [NSAttributedString.Key.font: moreTextFont, NSAttributedString.Key.foregroundColor: moreTextColor])
answerAttributed.append(readMoreAttributed)
self.attributedText = answerAttributed
}
}
var visibleTextLength: Int {
let font: UIFont = self.font
let mode: NSLineBreakMode = self.lineBreakMode
let labelWidth: CGFloat = self.frame.size.width
let labelHeight: CGFloat = self.frame.size.height
let sizeConstraint = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude)
if let myText = self.text {
let attributes: [AnyHashable: Any] = [NSAttributedString.Key.font: font]
let attributedText = NSAttributedString(string: myText, attributes: attributes as? [NSAttributedString.Key : Any])
let boundingRect: CGRect = attributedText.boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, context: nil)
if boundingRect.size.height > labelHeight {
var index: Int = 0
var prev: Int = 0
let characterSet = CharacterSet.whitespacesAndNewlines
repeat {
prev = index
if mode == NSLineBreakMode.byCharWrapping {
index += 1
} else {
index = (myText as NSString).rangeOfCharacter(from: characterSet, options: [], range: NSRange(location: index + 1, length: myText.count - index - 1)).location
}
} while index != NSNotFound && index < myText.count && (myText as NSString).substring(to: index).boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, attributes: attributes as? [NSAttributedString.Key : Any], context: nil).size.height <= labelHeight
return prev
}
}
if self.text == nil {
return 0
} else {
return self.text!.count
}
}
}
发布于 2019-09-22 10:11:03
class DynamicLabel: UILabel{
var fullText: String?
var truncatedLength = 100
var isTruncated = true
func collapse(){
let index = fullText!.index(fullText!.startIndex, offsetBy: truncatedLength)
self.text = fullText![...index].description + "... More"
isTruncated = true
}
func expand(){
self.text = fullText
isTruncated = false
}
}
这只是一个简单的技巧来完成所有这些杂乱的实现。想法很简单,我们不设置折叠或展开行,只需将标签设置为0。然后将原始文本存储在fullText
变量中。现在,如果我们想要显示折叠格式,那么只需获取substring并添加自定义省略号即可。
注意:这不包括点击事件处理程序,你可以自己在控制器上添加它。
发布于 2015-08-31 18:39:59
使用方法- boundingRectWithSize:options:attributes:context:并将您的字体作为NSFontAttributeName
键传递给NSAttributedString
将为您提供所需的正确rect。
因此,您需要检查它是否大于标签边界减去偏移量。只有在是的时候,你才需要裁剪你的文本并在最后显示Read More
。
https://stackoverflow.com/questions/32309247
复制相似问题