Один из наиболее распространенных ежедневных запросов - это управление строками HTML из бэкэнда, правильная их рендеринг в UILabel. В большинстве случаев приложение iOS должно сосуществовать с веб-аналогом, который анализирует HTML более эффективно, чем UILabel.

Все это было правдой до появления NSAttributedString, который вообще изменил правила игры. Объекты UILabel также могут принимать определенное значение в своих свойствах с именем attributedText:

let aLabel = UILabel()
aLabel.attributedText = NSAttributedString(string: “hello, world!”)

Очевидно, недостаточно использовать HTML-текст в качестве значения этого свойства ... иначе не было бы причин писать этот пост.

Вначале были расширения DIY, которые позволяли анализировать теги HTML, преобразовывая их в атрибуты для нашей NSAttributedString. В частности, я влюбился в одно из этих расширений. Я использовал его много раз в прошлом. Затем вышел Swift, и это расширение было устаревшим. В самом начале, когда проекты были не такими чистыми, как Objective-C и Swift, я продолжал заниматься этим. Однако за последние два года все стало немного сложнее, потому что мои проекты теперь полностью основаны на быстродействии, и я больше не хочу иметь дело с гибридным кодом.

Конечно, есть много других подобных расширений, написанных на Swift, но ни одно из них не дало мне «вау-эффекта», как указанное выше, по многим причинам: сложность, управление зависимостями и другие факторы. Короче, пришлось искать другой путь.

Случайно наткнулся на пост Деяна Атанасова. Оказывается, можно управлять HTML напрямую с помощью собственных компонентов Swift. Давайте взглянем на основную операцию, а затем я покажу вам, как я улучшил предложение Деяна.

NSAttributedString предоставляет конструктор, который принимает на вход RAW-версию строки в двоичном формате данных и некоторые другие параметры.

NSAttributedString(data:options:documentAttributes:)

Более того, - здесь происходит волшебство - если мы проинструктируем NSAttributedString использовать необработанный ввод как HTML-документ, результатом будет правильно инициализированный объект со всеми возможными атрибутами, извлеченными напрямую. из HTML-тегов. Потрясающие. Именно то, что мы искали.

Для любопытных есть еще один вариант. Можно вернуть объект, содержащий словарь всех параметров, используемых конвертером html, для последующего использования (например, может быть полезно выровнять другое содержимое в UIView, которое не является частью HTML-страницы).

Давайте посмотрим, как построить этот звонок:

В чем дело? Мы расширили поведение объекта String для обработки интересующего нас преобразования. Во-первых, мы гарантируем, что можем преобразовать нашу строку в данные; если операция по какой-либо причине не удалась, мы вернем nil. В противном случае давайте перейдем к конструкции try, которая, в свою очередь, вернет интересующее нас значение. Конструкция try catch позволяет нам обрабатывать любые исключения и возвращать nil на всякий случай.

Метод инициализации NSAttributedString (data: options: documentAttributes :) принимает двоичное значение строки как объект Data и необязательный словарь. Этот словарь определяет, что входными данными .documentType является HTML NSAttributedString.DocumentType.html, а также его кодировка .characterEncoding: String. Encoding.utf8.rawValue.

Все идет нормально. На этом этапе мы можем преобразовать HTML в NSAttributedString за один шаг:

aLabel.attributedText = “<b>Hello</b>,<i>world</i>”.html2Attributed

Потрясающие! Кстати, есть еще две основные проблемы, которые необходимо решить:

  • Вы заметите, что текст отображается с использованием шрифта по умолчанию, который серьезно отличается от того, к которому мы привыкли в iOS11.
  • Есть параметр, который мы не учли, и для него было установлено значение nil (documentAttributed).

Начнем с первой проблемы. Текст HTML по умолчанию отображается шрифтом Times New Roman. Для преодоления этой проблемы существует множество решений, и это зависит также от того, что мы хотим получить, а также от контекста нашей проблемы. Поскольку мы имеем дело с HTML, довольно гибкое решение предполагает использование CSS и глобального стиля html. Если бы у нас была простая HTML-страница, содержащая только наш текст, мы могли бы использовать CSS, подобный приведенному ниже, чтобы применить стиль текста ко всей HTML-странице:

<style>
html * {font-size: 12.0pt !important;color: #383838 !important;font-family: Helvetica !important;}
</style>
<b>hello</b>, <i>world</i>

Перенос этой концепции на быстрое расширение:

Намного лучше! Теперь наш HTML-текст вставлен в более сложный HTML-контекст, в котором используется CSS. Обратите внимание, как font-size, color и font-family параметризованы с использованием входных параметров, что делает метод довольно универсальным для использования в различных обстоятельствах.

Стоит отметить, как мы обрабатываем UIColor. Последний не содержит встроенного расширения для обработки шестнадцатеричного преобразования указанного цвета:

Наконец, что не менее важно, есть последний параметр documentAttributes, который мы еще не использовали. Но для чего это нужно? Этот параметр работает по ссылке (а не по значению), и в конце функции он заполняется некоторой полезной информацией о только что созданном тексте с атрибутами. Эти данные могут быть полезны для определения фактической области отображения экрана и другой служебной информации, которую в противном случае было бы трудно получить.

На этот раз расширение возвращает кортеж, а не одно значение. Таким образом, мы можем обрабатывать два важных значения за один проход: словарь атрибутов и его NSAttributedString.

Важно отметить, как словарь сначала создается, а затем передается для справки & в метод инициализации. Таким образом, когда мы вернемся из конструктора, у нас будет правильная оценка объекта.

Собери все вместе. Полное расширение, предлагающее различные методы для работы с различными ситуациями со строками, можно найти здесь:

Использованная литература: