Android textview and html

Текст с разметкой в android.widget.TextView

Недавно мне понадобилось сделать довольно хитроумный чат в приложении под Android. Помимо собственно информации требовалось передавать пользователям дополнительную функциональность в контексте определенного сообщения: имя автора сообщения по нажатию на него должно вставляться в текстовое поле ответа, а если это сообщение о только что созданном игровом сеансе, пользователи должны иметь возможность присоединиться к игре по клику и так далее. Одним из главных требований была возможность создавать сообщение, содержащее несколько ссылок, что и задало направление исследований.

WebView, обладая нужной функциональностью, был отвергнут по причине тяжести решения: я даже не стал создавать 100 или сколько-нибудь там экземпляров в тестовых целях, по одному на каждое сообщение, поскольку сразу было понятно, что это расточительство нормально работать не будет.

К счастью, самый обычный TextView обладает неожиданно потрясающей функциональностью по разметке текста и может использоваться как в качестве отдельного элемента, так и служить целой страницей, будучи несравненно легковеснее, чем WebView.

Я реализовал весь, необходимый мне функционал и выяснил ещё несколько довольно интересных вещей, столкнувшись с некоторым количеством подводных камней (впрочем, не очень острых). Можно сказать, всё нижеописанное — руководство по созданию достаточно мощной справочной системы в своём приложении практически даром.

Задачи

В данном примере мы создадим приложение с двумя Activity, одна из которых содержит TextView, исполняющий роль браузера, из которого, в частности, можно вызвать вторую Activity, демонстрирующую работу с параметрами вызова. Мы выясним, каким образом можно создавать страницы текста с разметкой и изображениями и связывать их ссылками.

Содержимое страниц берётся из строк в ресурсах приложения, а изображения являются drawable-ресурсами. Небольшие изменения в коде позволят использовать другие расположения.

Создание приложения

Любым удобным нам способом создаём обычное приложение:

Немного пояснений к манифесту. Если с первой Activity всё понятно, вторая (AnotherActivity) содержит некие дополнительные описатели.

android:exported=«false» необходимо для того, чтобы компилятор не выдавал предупреждения о том, что мы забыли что-то прописать в экспортируемом компоненте. На мой взгляд, чисто декоративный момент, но чем меньше жёлтых треугольничков — тем спокойнее.

Раздел intent-filter содержит описатели того, каким образом и при каких обстоятельствах будет происходить запуск Activity.

означает, что можно запустить Activity ссылкой вида activity-run://AnotherActivityHost?params.

Значения action и category необходимы системе для того чтобы обнаружить и запустить Activity.

Подготовка ресурсов

Строки, содержащие разметку, должны иметь аттрибут formatted со значением false, а содержимое должно передаваться в блоке CDATA, чтобы у компилятора не было претензий к разметке и специальным символам. В данном примере признаком статьи будет префикс article_ в названии строки.

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

Изображения могут быть формата jpg, png или gif без анимации. Анимированный gif отображается статичной картинкой. Расположение стандартное для ресурсов, для дисплеев разной плотности можно подготовить свой вариант картинки. В данном примере все изображения находятся в drawable-nodpi

Как всё работает

Рассмотрим некоторые части кода подробно.

TextView используемый нами в качестве браузера, требует особой инициализации:

tvContent.setLinksClickable(true); указывает на то, что ссылки в данном элементе реагируют на нажатие.

tvContent.setMovementMethod(new LinkMovementMethod()); назначает способ навигации по элементу. Использованный нами LinkMovementMethod интересен сам по себе и, возможно, заслуживает отдельной статьи. Я лишь скажу, что при необходимости более полного контроля можно создать его наследника, переопределенные методы которого позволят отслеживать все действия со ссылками в элементе.

Читайте также:  Flyme это андроид или

В данном методе происходит получение строки по идентификатору из строковых ресурсов, её преобразование из HTML в специальный объект Spanned, затем ещё одно преобразование в Spannable и установка в TextView в качестве содержимого. Всё это кажется довольно громоздким, но тому есть причины.

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

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

Более интересен нам будет Html.TagHadler:

Здесь у нас происходит несколько интересных вещей.

При преобразовании из HTML в Spanned методом Html.fromHtml, обрабатываются тэги br , p , div , em , b , strong , cite , dfn , i , big , small , font , blockquote , tt , a , u , sup , sub , h1. h6 и img . В случае, если тэг не опознан, вызывается Html.TagHandler (если, конечно, он передан в вызов).

Мы проверяем, не является ли переданный тэг «нашим» и если это так, создаём соответствующий Span — элемент разметки, а затем накладываем его на текст. Я создал несколько собственных Span-ов, они будут рассмотрены далее. Как правило, Span-ы наследуются от android.text.style.CharacterStyle.

К сожалению, у меня не получилось малой кровью добиться центрования отдельных строк или абзацев, а встроенной возможности для этого не существует. Также, нельзя прочесть атрибуты тэга из xmlReader, поскольку он реализован не полностью. По этой причине пришлось изобретать свой способ передачи параметров: значение является частью тега. В нашем примере таким образом передаётся значение цвета в тэге color, преобразовываемом в ParameterizedSpan. Получается что-то вроде красный . Это достаточно ограниченный и не очень удобный способ, но иногда лучше такой, чем никакого.

Этот код делает следующее: В случае, если передан открывающий Span, он добавляется к концу строки в текущем её виде. В случае, если Span закрывающий, мы находим в строке его открывающий аналог, запоминаем его положение, затем удаляем и добавляем новый, но уже с информацией о начальном положении и длине.

Мы завершили рассмотрение класса Activity, являющегося основным модулем нашего приложения. Теперь рассмотрим вспомогательные классы.

Это Span общего назначения и с его помощью можно задать большинство параметров стиля текста. Его можно использовать как базу для создания стилей текста из собственных тэгов.

Этот класс описывает элемент, который по нажатию на него обеспечивает переход к статье, чей идентификатор является его параметром. Здесь я применил производное от способа, описанного мной ранее: сам тэг является собственным параметром, а его класс определяется префиксом article_. Поднимемся выше, к описанию Html.TagHandler:

Обработчик тэгов, увидев тэг, начинающийся на article_, создаёт ArticleSpan, задавая ему в качестве параметра название тэга. Элемент, при нажатии на него, вызывает метод MainActivity.setArticle, после чего в TextView устанавливается новый текст.

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

Конечно, всё описанное является вариациями одного принципа, каждый выберёт то, что ему удобнее.

Вызов Activity

В HTML мы видим следующее:

При нажатии на ссылку, происходит вызов AnotherActivity с передачей параметров в Intent. Эти параметры можно получить и использовать:

Использованные материалы

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

Я очень рад, что существует на свете StackOverflow.com.

Архив с исходниками проекта

Архив с исходными текстами и ресурсами проекта можно взять здесь.

Источник

Как отображать HTML в TextView?

У меня простой HTML :

Я хочу отобразить текст в стиле HTML в TextView . Как это сделать .

Любая помощь будет оценена по достоинству.

Вам нужно использовать Html.fromHtml() для использования HTML в ваших XML-строках. Просто ссылаясь на String с HTML в вашем макете, XML не будет работать.

Читайте также:  Android 10 build prop где находится

Например (> = Android Nougat):

Чтобы различать версии Android, используйте Build.VERSION.SDK_INT >= Build.VERSION_CODES.N .

Это тоже хорошо!

Он работает только для нескольких тегов.

SetText (Html.fromHtml (bodyData)) устарел после api 24. Теперь вам нужно сделать следующее:

Если вы хотите настроить его через xml без каких-либо изменений в java-коде, вы можете найти эту идею полезной. Просто вы вызываете init из конструктора и устанавливаете текст как html

Следующий код дал лучший результат для меня.

Если вы пытаетесь показать HTML из идентификатора строкового ресурса, форматирование может не отображаться на экране. Если это происходит с вами, попробуйте использовать теги CDATA:

См. Это сообщение для более подробной информации.

Стоит отметить, что метод Html.fromHtml (источник String) устарел с уровня API 24. Если это ваш целевой API, вместо этого вы должны использовать Html.fromHtml (String source, int flags) .

Если вы просто хотите отобразить некоторый текст html и не нуждаетесь в TextView , тогда возьмите WebView и используйте его, как WebView ниже:

Это не ограничивает вас несколькими тегами html.

Лучший подход к использованию разделов CData для строки в файле strings.xml для получения фактического отображения содержимого html в TextView в приведенном ниже фрагменте кода даст вам справедливую идею.

Раздел CData в тексте строки сохраняет данные тега html без изменений даже после форматирования текста с использованием метода String.format. Итак, Html.fromHtml (str) отлично работает, и вы увидите жирный текст в приветственном сообщении.

Вывод:

Добро пожаловать в ваш любимый магазин музыкальных приложений. Вы вошли как: имя пользователя

Простое использование Html.fromHtml(«html string») . Это сработает. Если в строке есть теги, такие как

тогда появятся пробелы. Но мы не можем устранить эти пространства. Если вы все же хотите удалить пробелы, вы можете удалить теги в строке, а затем передать строку методу Html.fromHtml(«html string»); , Также, как правило, эти строки исходят от сервера (динамического), но не часто, если лучше передать строку, как это относится к методу, чем пытаться удалить теги из строки.

Использование почти такое же, как и для Android-преобразователя по умолчанию:

Нашел его после того, как я уже начал собственную реализацию html в spannable converter, потому что стандартный Html.fromHtml не обеспечивает достаточной гибкости для управления рендерингом и даже не имеет возможности использовать пользовательские шрифты из ttf

Я реализовал это с помощью веб-представления. В моем случае мне приходится загружать изображение из URL вместе с текстом в текстовом виде, и это работает для меня.

Было предложено использовать различные ответы для использования класса фреймворка Html, как предлагается здесь, но, к сожалению, этот класс имеет различное поведение в разных версиях Android и различные неподтвержденные ошибки, о чем свидетельствуют проблемы 214637 , 14778 , 235128 и 75953 .

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

Хотя он похож на класс Html структуры, некоторые изменения подписей потребовались, чтобы разрешить больше обратных вызовов. Вот пример с страницы GitHub:

Источник

TextView

Компонент TextView предназначен для отображения текста без возможности редактирования его пользователем, что видно из его названия (Text — текст, view — просмотр).

Находится в разделе Texts.

TextView — один из самых используемых компонентов. С его помощью пользователю удобнее ориентироваться в программе. По сути, это как таблички: Руками не трогать, По газону не ходить, Вход с собаками воспрещен, Часы работы с 9.00 до 18.00 и т.д., и служит для представления пользователю описательного текста.

Для отображения текста в TextView в файле разметки используется атрибут android:text, например:

Такой подход является нежелательным. Рекомендуется всегда использовать текстовые ресурсы. В будущем эта привычка позволит вам обеспечить многоязыковую поддержку:

Программная установка текста

Программно текст можно задать методом setText():

Атрибуты

Для всех вышеперечисленных атрибутов в классе TextView есть соответствующие методы для чтения или задания соответствующих свойств.

Программно установим размеры текста при помощи setTextSize() с различными единицами измерения.

По умолчанию у компонентов TextView отсутствует фоновый цвет. Чтобы задать цвет, укажите значение Drawable для атрибута android:background. В качестве значения Drawable может использоваться изображение или XML-представление фигуры, включающий ресурс Drawable (поместить в папку res/drawable).

Читайте также:  Прошивка для андроид самсунг 9300

Программная установка фона

В некоторых случаях программисты из-за невнимательности неправильно меняют фон элемента программным способом и удивляются, почему ничего не работает.

Предположим, у вас определён в ресурсах зелёный цвет:

Следующий код будет ошибочным:

Нужно так (два варианта):

Реагируем на событие onClick

Если вы хотите, чтобы TextView обрабатывал нажатия (атрибут android:onClick), то не забывайте также использовать в связке атрибут android:clickable=»true». Иначе работать не будет!

Многострочный текст

Если вы хотите создать многострочный текст в TextView, то используйте символы \n для переноса строк.

Например, в ресурсах:

Обратите внимание, что в тексте также применяется простое форматирование.

Также перенос на новую строку можно задать в коде:

Увеличиваем интервалы между строками

Вы можете управлять интервалом между соседними строчками текста через атрибут android:lineSpacingMultiplier, который является множителем. Установите дробное значение меньше единицы, чтобы сократить интервал или больше единицы, чтобы увеличить интервал между строками.

Бой с тенью

Чтобы оживить текст, можно дополнительно задействовать атрибуты для создания эффектов тени: shadowColor, shadowDx, shadowDy и shadowRadius. С их помощью вы можете установить цвет тени и ее смещение. Во время установки значений вы не увидите изменений, необходимо запустить пример в эмуляторе или на устройстве. В следующем примере я создал тень красного цвета со смещением в 2 пикселя по вертикали и горизонтали. Учтите, что для смещения используются единицы px (пиксели), единицы dp не поддерживаются.

Программный эквивалент — метод public void setShadowLayer (float radius, float dx, float dy, int color):

Создание ссылок автоматом

У TextView есть ещё два интересных свойства Auto link (атрибут autoLink) и Links clickable (атрибут linksClickable), которые позволяют автоматически создавать ссылки из текста.

Выглядит это следующим образом. Предположим, мы присвоим элементу TextView текст Мой сайт: developer.alexanderklimov.ru и применим к нему указанные свойства.

При этом уже на этапе разработки вы увидите, что строка адреса сайта после слов Мой адрес: стала ссылкой. Если вы запустите приложение и нажмете на ссылку, то откроется браузер с указанным адресом. Вам даже не придется писать дополнительный код. Аналогично, если указать номер телефона (параметр phone), то запустится звонилка.

У ссылки есть интересная особенность — при длительном нажатии на ссылку появляется диалоговое окно, позволяющее скопировать ссылку в буфер обмена.

Атрибут autoLink позволяет комбинировать различные виды ссылок для автоматического распознавания: веб-адрес, email, номер телефона.

Цвет ссылки можно поменять через свойство Text color link (XML-атрибут textColorLink), а программно через метод setTextLinkColor().

Программно можно установить ссылки на текст через класс Linkify:

Кроме константы ALL, можно также использовать Linkify.EMAIL_ADDRESSES, Linkify.MAP_ADDRESSES, Linkify.PHONE_NUMBERS. К сожалению, русские адреса не распознаются. В моём случае индекс был распознан как телефонный номер, а город и улица не стали ссылкой.

В таких случаях придётся самостоятельно добавить ссылки в текстах. Например, определим ссылку в ресурсе:

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

Ссылки в тексте выглядят не совсем удобными. Есть отдельная библиотека, которая улучшает функциональность. Описание проблем и ссылка на библиотеку есть в статье A better way to handle links in TextView — Saket Narayan.

Совет: Используйте полупрозрачность с умом

Если вам нужно установить текст полупрозрачным, то не используйте атрибут android:alpha:

Дело в том, что такой подход затрачивает много ресурсов при перерисовке.

Атрибут textColor позволяет установить полупрозрачность без потери производительности:

Выделить текст для копирования

По умолчанию, текст в TextView нельзя выделить для копирования. Но в API 11 появилась такая возможность, которая может пригодиться. Делается либо при помощи XML-атрибута android:textIsSelectable, либо через метод setTextIsSelectable().

Добавьте в разметку два компонента TextView и одно текстовое поле EditText для вставки скопированного текста. У первой текстовой метки установим возможность выделения текста декларативно.

Для второго компонента возможность выделения создадим программно.

Сделайте долгий тап на тексте в любом TextView. Увидите стандартные ползунки для выбора длины текста. Скопируйте текст, сделайте длинный тап в EditText и вставьте текст.

Источник

Оцените статью