У меня есть атрибутированная строка в 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
*
Итак, в основном я хочу, чтобы значок склеивался с последней частью имени пользователя (если это возможно). Если имя пользователя не содержит пробелов и слишком длинное, его следует просто перенести на следующую строку, потому что это стандартная реализация. Какие-либо предложения?
К сожалению, это не соответствует моему дизайну. Ситуация не типичная - обычно имя пользователя действительно усекается и не переносится на несколько строк, однако бывают ситуации, когда это может произойти. Пример, когда это происходит сейчас, — это предоставление отзыва о лайках под публикацией: Username, username and 13 others liked your post.
— это может привести к усечению двух длинных имен пользователей, и это может произойти прямо перед значком, поэтому я хочу сохранить их вместе.
Хорошо, сейчас я понимаю. Просто предложение, так что вам, очевидно, не нужно этого делать, но вы можете создать пользовательский интерфейс, похожий на Twitter, на мобильном телефоне. При переходе в раздел уведомлений будут подряд фотографии профиля. Внизу написано что-то вроде Username and 2 others liked your reply
. Может быть, это могло бы выглядеть чище и организованнее?
Это возможность показать фотографии профиля. Было бы неплохо показать это как Twitter, Instagram и другие социальные сети, где он показывает первые, скажем, 10 фотографий профиля и +13 в конце. Однако это было бы немного странно, когда лайков всего один или два. Поэтому сейчас мы ищем способ отобразить его в следующих ситуациях: Username liked your post.
, Username and Username liked your post
, и если будет больше лайков, он перейдет в Username, Username and 1 other liked your post.
- но проблема заключается в том, что я спросил в OP.
Для протокола: речь идет не об уведомлениях, а о публикации и отображении лайков под ней. Подумайте о ленте Instagram, прямо под изображением.
Я сделал изображение, я думаю, вы хотите, чтобы оно выглядело как это? Не стесняйтесь добавлять его в свой пост, если это то, что вы хотите.
Точно. Сейчас я изучаю решение, предоставленное @ajeferson, которое выглядит очень многообещающе, если вас это интересует.
Я просто осматриваюсь :)
Ну, я не уверен, что вы можете сделать это, установив какую-то опцию в 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
}
Конечно, вы захотите удалить принудительное развертывание и другие не очень хорошие методы. Но это только для краткости. Надеюсь, вы уловили идею.
Очень интересный подход. Это также будет работать, когда в моей строке есть 2 имени пользователя, верно? Как это работает на последнем компоненте. Например. строка может быть «Имя пользователя *, имя пользователя * и 12 другим понравилось ваше сообщение», она будет обрезана во втором, верно?
Да, это должно закрепиться на последнем.
Не лучше ли заранее получить изображение, а имя пользователя после? Затем вы можете использовать
.lineBreakMode = .byTruncatingTail
, чтобы имя пользователя заканчивалось наa very long user...
, если оно слишком длинное. Я просто думаю, что это выглядело бы визуально неправильно, если бы имя пользователя переносилось на несколько строк.