Храните текст и изображение вместе в 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
*

Итак, в основном я хочу, чтобы значок склеивался с последней частью имени пользователя (если это возможно). Если имя пользователя не содержит пробелов и слишком длинное, его следует просто перенести на следующую строку, потому что это стандартная реализация. Какие-либо предложения?

Не лучше ли заранее получить изображение, а имя пользователя после? Затем вы можете использовать .lineBreakMode = .byTruncatingTail, чтобы имя пользователя заканчивалось на a very long user..., если оно слишком длинное. Я просто думаю, что это выглядело бы визуально неправильно, если бы имя пользователя переносилось на несколько строк.

George 06.04.2019 21:54

К сожалению, это не соответствует моему дизайну. Ситуация не типичная - обычно имя пользователя действительно усекается и не переносится на несколько строк, однако бывают ситуации, когда это может произойти. Пример, когда это происходит сейчас, — это предоставление отзыва о лайках под публикацией: Username, username and 13 others liked your post. — это может привести к усечению двух длинных имен пользователей, и это может произойти прямо перед значком, поэтому я хочу сохранить их вместе.

PennyWise 06.04.2019 21:59

Хорошо, сейчас я понимаю. Просто предложение, так что вам, очевидно, не нужно этого делать, но вы можете создать пользовательский интерфейс, похожий на Twitter, на мобильном телефоне. При переходе в раздел уведомлений будут подряд фотографии профиля. Внизу написано что-то вроде Username and 2 others liked your reply. Может быть, это могло бы выглядеть чище и организованнее?

George 06.04.2019 22:04

Это возможность показать фотографии профиля. Было бы неплохо показать это как Twitter, Instagram и другие социальные сети, где он показывает первые, скажем, 10 фотографий профиля и +13 в конце. Однако это было бы немного странно, когда лайков всего один или два. Поэтому сейчас мы ищем способ отобразить его в следующих ситуациях: Username liked your post., Username and Username liked your post, и если будет больше лайков, он перейдет в Username, Username and 1 other liked your post. - но проблема заключается в том, что я спросил в OP.

PennyWise 06.04.2019 22:09

Для протокола: речь идет не об уведомлениях, а о публикации и отображении лайков под ней. Подумайте о ленте Instagram, прямо под изображением.

PennyWise 06.04.2019 22:10

Я сделал изображение, я думаю, вы хотите, чтобы оно выглядело как это? Не стесняйтесь добавлять его в свой пост, если это то, что вы хотите.

George 06.04.2019 22:35

Точно. Сейчас я изучаю решение, предоставленное @ajeferson, которое выглядит очень многообещающе, если вас это интересует.

PennyWise 06.04.2019 22:36

Я просто осматриваюсь :)

George 06.04.2019 22:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
876
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ну, я не уверен, что вы можете сделать это, установив какую-то опцию в 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 другим понравилось ваше сообщение», она будет обрезана во втором, верно?

PennyWise 06.04.2019 22:34

Да, это должно закрепиться на последнем.

alanpaivaa 06.04.2019 22:46

Другие вопросы по теме