- Пространство имён Tools
- tools:ignore
- tools:targetApi
- tools:locale
- tools:context
- tools:layout
- tools:showIn
- tools:menu
- tools:actionBarNavMode
- tools:listitem / listheader / listfooter
- tools:layoutManager
- tools:itemCount
- tools:openDrawer
- tools:minValue/tools:maxValue
- tools:src
- tools:layout_height/tools:layout_width
- tools:background
- tools:src=»http://developer.alexanderklimov.ru/android/studio/@tools:sample/»
- Текст с разметкой в android.widget.TextView
- Задачи
- Создание приложения
- Подготовка ресурсов
- Как всё работает
- Вызов Activity
- Использованные материалы
- Архив с исходниками проекта
Пространство имён Tools
При создании нового проекта, когда вы проектировали макет для экрана активности, то, наверняка, замечали загадочные строчки у корневого элемента со словом tools:
Настало время сорвать покровы и использовать новые возможности.
Привычное пространство имён xmlns:android позволяет настраивать внешний вид и поведение компонентов в Android-приложении. А новое пространство имён xmlns:tools позволяет среде разработки (в нашем случае, Android Studio) правильно отобразить компоненты для просмотра в режиме дизайна.
Причём возможности данного инструмента гораздо выше, чем многие себе представляют.
Для начала приведу простой пример, который многие оценят по достоинству. Представьте себе, что у вас есть компонент пустой TextView, который получает текст с сервера. Чтобы визуально представить себе, как будет выглядеть текст, не соединяясь с сервером, вам нужно временно присвоить какой-нибудь текст. А потом не забыть удалить его при создании релиза. А можно поступить проще. Инструмент tools дублирует многие визуальные атрибуты пространства имён android и вы можете заменить его следующим образом.
В реальности у текстовой метки нет текста, но в окне предварительного просмотра вы можете видеть текст и оценить дизайн. Напомню, что эта настройка относится только к среде разработки, а не к вашему приложению. Поэтому теперь можно не волноваться, что однажды вы забудете удалить временный текст. Попробуйте теперь поменять цвет фона с помощью атрибута tools:background =»#ваш_цвет». Получилось?
Кроме визуальных атрибутов, tools может использоваться для взаимодействия с инструментом Lint, который пытается подсказать при проблемном коде. К этим атрибутам можно отнести
tools:ignore
Атрибут tools:ignore похож по своему поведению на Java-аннотацию @SuppressWarnings, подсказывающему инструменту Lint не обращать внимания на код. Аналогично можно не обращать на какой-то атрибут в XML-файле.
Самый распространённый случай — использование ImageView. Lint всегда недоволен, если у данного компонента нет атрибута android:contentDescription. Профессионально сделанное приложение должно использовать данный атрибут. Но в некоторых ситуациях ImageView может быть вспомогательным элементом экрана, не несущим смысловой нагрузки, например, разделитель. И тогда можно подавить предупреждение следующим образом.
tools:targetApi
Атрибут tools:targetApi работает аналогично аннотации @TargetApi и говорит о минимальной версии API, которая будет использована для ресурсов.
Например, ваш проект использует минимальный уровень minSdkLevel = 15, а вы используете объекты RippleDrawable в качестве ресурсов в общей папке, а не в папке drawable-v21. Но если вы контролируете ситуацию и знаете, что для старых устройств есть другие ресурсы, то можете подавить предупреждение:
tools:locale
Атрибут tools:locale поможет вам подавить предупреждения Lint о неправильном правописании, выступая в качестве грамар-наци. Проблема в том, что Lint содержит проверку орфографии только на английском языке. И если ваши строковые ресурсы содержат русский текст, то его предупреждения бесполезны. Отключаем их:
Рассмотрим теперь другие доступные атрибуты.
tools:context
Атрибут tools:context у корневого элемента позволяет определить связь между макетом и классом активности, в которой данный макет будет реализован. Помогает студии сформировать в окне предварительного просмотра внешний вид, подтягивая нужную тему.
tools:layout
Атрибут tools:layout используется в разметке фрагмента, чтобы вывести макет фрагмента на экране активности.
tools:showIn
Атрибут tools:showIn позволяет указать, какую разметку нужно использовать для вывода в окне предварительного просмотра. Это может пригодиться для тега merge:
tools:menu
Атрибут tools:menu подсказывает среде разработке, какое меню нужно отобразить в окне предварительного просмотра. Также используется в корневом элементе разметки.
Можно через запятую указать несколько меню, заданных в папке res/menu. Также кроме имени XML-файла можно использовать идентификаторы меню без символа @. В окне предварительного просмотра вы можете вызвать меню и нажать на пункт меню — вас сразу перенесёт в нужный файл.
Если не хотите выводить меню, то оставьте пустую строку. Данный атрибут не работает с темой Theme.AppCompat и производных от неё.
tools:actionBarNavMode
Атрибут tools:actionBarNavMode отвечает за внешний вид панели действий ActionBar. Он также размещается в корневом элементе разметки, не работает с темами Theme.AppCompat и Theme.Material и не действует при использовании Toolbar вместо ActionBar.
Доступны три варианта:
tools:listitem / listheader / listfooter
Также можно настроить внешний вид компонентов на основе AdapterView — ListView, GridView, ExpandableListView и т.д., указав нужную разметку для отдельных элементов списка, а также заголовка и футера. Появилась поддержка и RecyclerView.
Атрибуты для заголовка и футера могут работать только для ListView, а для GridView не работает.
Для сравнения как выглядят экраны активности с использованием tools: и без него.
Мы видим вкладки, элементы меню, другую разметку для списка.
tools:layoutManager
В RecyclerView можно использовать менеджер разметок с указанием различных параметров.
tools:itemCount
Обычно студия выводит десять элементов списка в RecyclerView. Вы можете изменить это поведение данным атрибутом.
tools:openDrawer
В студии 1.4 появился новый атрибут tools:openDrawer, управляющий состоянием навигационной шторки для DrawerLayout. При значении start будет показана шторка в выдвинутом виде. Доступны значения: start, end, left, right.
tools:minValue/tools:maxValue
Атрибуты для компонента NumberPicker для задания минимального и максимального значения.
tools:src
Можно указать графический ресурс. Полезно для ImageView, когда используется пустое изображение при запуске приложения и затем скачивается картинка с сервера. Позже появилась другая удобная возможность (см. ниже)
tools:layout_height/tools:layout_width
Ширина и высота.
tools:background
tools:src=»http://developer.alexanderklimov.ru/android/studio/@tools:sample/»
В студии версии 3.0 появились новые возможности. Теперь вы можете задать аватар, имя и случайный текст без создания собственных ресурсов. Это бывает полезно, когда ресурсы берутся из внешнего источника. Вам не нужно создавать временные ресурсы, которые увеличивают размер приложения и которые можно забыть удалить.
Например, можно задать изображение для ImageView:
Если у вас несколько ImageView, то изображения будут разными! Просмотреть весь набор можно в папке ..\plugins\android\lib\sampleData.
Можно задать текст для TextView:
- tools:text=»@tools:sample/full_names» — полное имя (также first_names, last_names)
- tools:text=»@tools:sample/cities» — город
- tools:text=»@tools:sample/us_zipcodes» — индексы США
- tools:text=»@tools:sample/us_phones» — телефонные номера США в формате (800) 555-xxxx
- tools:text=»@tools:sample/date/ddmmyy» — дата (date/day_of_week, date/mmddyy, date/hhmm, date/hhmmss)
- tools:text=»@tools:sample/lorem» — случайный текст
- tools:text=»@tools:sample/lorem/random» — большой случайный текст
Можно задать случайный фон
Пример применения некоторых атрибутов.
Но это ещё не всё. Если вас не устраивают изображения (там нет котов!) или тексты, предлагаемые студией, то можно задать свои изображения и тексты. Из контекстного меню папки res выбираем New | Sample Data Directory. В модуле app появится папка sampleData. Создайте текстовый файл с именем names и добавьте построчно различные имена: Барсик, Мурзик, Рыжик, Васька и т.д.
Заменим tools:text=»@tools:sample/full_names» на tools:text=»@sample/names». Теперь вместо непонятных иностранных имён будут отображаться правильные нормальные имена.
По такому же принципу можно создать собственные изображения для аватаров. В папке sampleData создайте подпапку avatars (имя произвольное) и разместите в ней нужные файлы изображений.
Используем атрибут для аватаров — tools:src=»http://developer.alexanderklimov.ru/android/studio/@sample/avatars».
Можно создать сложный вариант сочетаний имён и городов. Опять в той же папке sampleData создаём JSON-файл следующего содержания.
Можете обращаться к созданному файлу через атрибуты:
Источник
Текст с разметкой в 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 интересен сам по себе и, возможно, заслуживает отдельной статьи. Я лишь скажу, что при необходимости более полного контроля можно создать его наследника, переопределенные методы которого позволят отслеживать все действия со ссылками в элементе.
В данном методе происходит получение строки по идентификатору из строковых ресурсов, её преобразование из 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.
Архив с исходниками проекта
Архив с исходными текстами и ресурсами проекта можно взять здесь.
Источник