在 AttributedString 中将文本和图像放在一起
Keep text and image together in AttributedString
我在 Swift 中有一个属性字符串,它在用户名旁边显示一个图标。这很好用,我的实现如下所示:
attributedUsername = NSMutableAttributedString(string: "username")
let iconAttachment = NSTextAttachment()
let iconImage = UIImage(named: "userIcon")
iconAttachment.image = iconImage
iconAttachment.bounds = CGRect(x: 0, y: -3, width: 14, height: 14)
let iconString = NSAttributedString(attachment: verifiedAttachment)
attributedUsername.append(iconString)
usernameLabel.attributedText = attributedUsername
然而,有时用户名太大而无法放在一行中,将用户名换行在第二行 (numberOfLines = 0
)。这没问题,但如果用户名的长度刚好可以显示在屏幕上,那么图像就会换行到下一行。我想知道是否有任何方法可以将图标包裹到用户名的末尾。我希望实现的目标是:
username *
longer username *
a very long
username *
而不是:
username *
longer username *
a very long username
*
所以基本上我希望图标与用户名的最后一部分粘在一起(如果可能的话)。如果用户名不包含空格并且太长,那么它应该放在下一行,因为这是标准实现。有什么建议吗?
嗯,我不确定你是否可以通过在 NSAttributedString
中设置一些选项来做到这一点,但你可以通过简单的算法轻松实现。
首先,将创建属性字符串的代码移至一个函数,因为我们将使用它来计算宽度。确保还设置了字体属性,这样就可以从属性字符串中获得正确的大小:
func attributedString(for text: String) -> NSAttributedString {
let attributedText = NSMutableAttributedString(string: text)
let iconAttachment = NSTextAttachment()
let iconImage = UIImage(named: "star")
iconAttachment.image = iconImage
iconAttachment.bounds = CGRect(x: 0, y: -3, width: 14, height: 14)
let iconString = NSAttributedString(attachment: iconAttachment)
attributedText.append(iconString)
attributedText.setAttributes([.font: UIFont(name: "Avenir-Book", size: 15)!],
range: NSRange((text.startIndex..<text.endIndex), in: text))
return attributedText
}
然后:
let text = "some really really really really long usernameeeeeeeee"
let attributedText = attributedString(for: text)
let maxWidth = ...
if attributedText.size().width > maxWidth { // A line break is required
let lastWord = text.components(separatedBy: " ").last!
let attributedLastWord = attributedString(for: lastWord)
if attributedLastWord.size().width < maxWidth { // Forcing image to stick to last word
var fixedText = text
fixedText.insert("\n", at: text.index(text.endIndex, offsetBy: -lastWord.count))
label.attributedText = attributedString(for: fixedText)
} else {
label.attributedText = attributedText
}
} else {
label.attributedText = attributedText
}
当然,您会想要删除强制展开和其他不太好的做法。不过,这些只是为了简洁起见。我希望你明白了。
我在 Swift 中有一个属性字符串,它在用户名旁边显示一个图标。这很好用,我的实现如下所示:
attributedUsername = NSMutableAttributedString(string: "username")
let iconAttachment = NSTextAttachment()
let iconImage = UIImage(named: "userIcon")
iconAttachment.image = iconImage
iconAttachment.bounds = CGRect(x: 0, y: -3, width: 14, height: 14)
let iconString = NSAttributedString(attachment: verifiedAttachment)
attributedUsername.append(iconString)
usernameLabel.attributedText = attributedUsername
然而,有时用户名太大而无法放在一行中,将用户名换行在第二行 (numberOfLines = 0
)。这没问题,但如果用户名的长度刚好可以显示在屏幕上,那么图像就会换行到下一行。我想知道是否有任何方法可以将图标包裹到用户名的末尾。我希望实现的目标是:
username *
longer username *
a very long
username *
而不是:
username *
longer username *
a very long username
*
所以基本上我希望图标与用户名的最后一部分粘在一起(如果可能的话)。如果用户名不包含空格并且太长,那么它应该放在下一行,因为这是标准实现。有什么建议吗?
嗯,我不确定你是否可以通过在 NSAttributedString
中设置一些选项来做到这一点,但你可以通过简单的算法轻松实现。
首先,将创建属性字符串的代码移至一个函数,因为我们将使用它来计算宽度。确保还设置了字体属性,这样就可以从属性字符串中获得正确的大小:
func attributedString(for text: String) -> NSAttributedString {
let attributedText = NSMutableAttributedString(string: text)
let iconAttachment = NSTextAttachment()
let iconImage = UIImage(named: "star")
iconAttachment.image = iconImage
iconAttachment.bounds = CGRect(x: 0, y: -3, width: 14, height: 14)
let iconString = NSAttributedString(attachment: iconAttachment)
attributedText.append(iconString)
attributedText.setAttributes([.font: UIFont(name: "Avenir-Book", size: 15)!],
range: NSRange((text.startIndex..<text.endIndex), in: text))
return attributedText
}
然后:
let text = "some really really really really long usernameeeeeeeee"
let attributedText = attributedString(for: text)
let maxWidth = ...
if attributedText.size().width > maxWidth { // A line break is required
let lastWord = text.components(separatedBy: " ").last!
let attributedLastWord = attributedString(for: lastWord)
if attributedLastWord.size().width < maxWidth { // Forcing image to stick to last word
var fixedText = text
fixedText.insert("\n", at: text.index(text.endIndex, offsetBy: -lastWord.count))
label.attributedText = attributedString(for: fixedText)
} else {
label.attributedText = attributedText
}
} else {
label.attributedText = attributedText
}
当然,您会想要删除强制展开和其他不太好的做法。不过,这些只是为了简洁起见。我希望你明白了。