Android свои xml атрибуты

Somethings

problems and solutions

среда, 15 декабря 2010 г.

Создание атрибутов разметки для собственных компонентов в Android

Относительно недавно мы рассматривали способ, как писать собственые компоненты на примере VerticalProgressBar . Однако была в той реализации некоторая некрасивость: свойства компонента (такие как progress и max ) можно было инициализировать только в коде:

А было бы лучше выставлять их прямо в XML-разметке. В этой статье мы разберем, как это делается.

Новых компонентов выдумывать не будем, рассмотрим тот же VerticalProgressBar .

Объявление атрибутов

Атрибуты объявляются в ресурсах. Создадим файл attrs.xml и добавим в него следующее содержимое:

attrs.xml

У атрибута есть название ( name ) и тип ( format ). В данном случае мы навесили на наш компонент два стандартных андроидовских атрибута. format для них указывать не нужно и даже вредно, т.к. возникнет ошибка «Attribute has already been defined». К слову, список стандартных атрибутов можно увидеть в исходниках андроида (

Для полноты картины добавим еще два собственных атрибута — в которых можно будет задавать цвет прогресса:

attrs.xml

Тут уже все по-честному, format задается, а префикс android не пишется.

Чтение значений

Итак, атрибуты объявлены, нужно их как-то прочитать. Как известно, у View имеется конструктор со следующей сигнатурой:

Он вызывается при создании компонента из XML-разметки. А в параметре attrs передаются все атрибуты, указанные в разметке для данного компонента. Отсюда-то мы и станем их читать:

VerticalProgressBar.java

Использование

Теперь в XML-разметке активности можно писать вот так:

main.xml

И наблюдать следующий результат:

Заключение

Итак, мы рассмотрели, как навешивать на компонент произвольные атрибуты. Причем, как стандартные андроидские, так и собственные.

Источник

Введение

Это будет серия постов на тему создания пользовательского view компонента для Android. Я покажу как нарисовать содержимое компонента, как работают layouting и measuring, как реализовать view groups и как анимировать содержимое компонента. В этом посте я объясню, как расширить стандартный view, как его использовать и как создать свои собственные xml атрибуты.

Специфические задачи, специфические view

Стандартные view компоненты, которые предоставляет Android, могут использоваться для многих задач и ситуаций. Тем не менее, в наших приложениях наибольшую часть кода часто занимает конфигурация этих view для специфических задач. Этот конфигурационный код часто находится в activity вашего приложения, поэтому их сложно содержать в чистоте. А при наличии большого количества различного кода возникают сложности и с его разделением в отдельные классы.

Предположим, вы работаете над приложением, которое содержит статистику тренировок пользователя. Например, общая дистанция, общее время и так далее, в зависимости от типа тренинга. Для того чтобы отображать данные в удобном виде, вы решили их адаптировать, основываясь на их продолжительности. Если это 2378 секунд, вы хотите отображать это время как «40 минут», а если это 18550 секунд, то лучше было бы отображать на дисплей «5 часов 9 минут».

Создание custom view

Один из способов решения этой задачи — создать специализированный view, который будет должным образом обрабатывать ваш текст. Давайте начнем с создания нашего собственного класса DurationTextView, который будет расширять класс TextView.

TextView, как и все view классы, имеет три различных конструктора: первый просто принимает контекст (Context), второй принимает контекст и набор атрибутов (AttributeSet), а третий еще дополнительно принимает стиль «по умолчанию». В большинстве случаев вам достаточно реализовать второй конструктор, который показан выше.

Теперь мы создали view и чтобы его использовать, мы добавим его в файл разметки:

Обратите внимание, вам необходимо полностью указывать имя вашего класса, который вы реализовали.

В данный момент этот класс практически идентичен стандартному TextView, поэтому давайте добавим ему некоторую функциональность.

Добавление логики отображения

Поскольку этот view будет отображать длительность, давайте добавим метод setDuration().

Что делает этот метод? Он получает значение длительности, переводит его в текстовую строку в определенном формате, используя некую логику, а затем выводит с помощью метода setText(). В данном случае логика заключается в переводе секунд в минуты и дальнейшем разделении на часы и минуты. Также в методе присутствует логика для корректного отображения одной минуты: «1 minute» вместо «1 minute(s)».

В конце метода отформатированное время преобразуется в строку с помощью шаблона.

private static final String TEMPLATE = «Duration: %s«;

Шаблон начинается со слова «Duration», а далее жирными буквами отображается отформатированная строка.

Читайте также:  Easy connect как подключить андроид

Для простоты я использовал в коде строковые литералы. В нормальном коде, эти строковые литералы лучше перенести в strings.xml, это позволяет в дальнейшем локализовать их.

Использование полученного view

Попробуем использовать наш view. В xml файл разметки добавим 5 custom View.

А в activity в методе onCreate() после метода setContentView() добавим следующие строки.

Соберем проект и загрузим его в эмулятор. Полученный результат можно видеть на изображении ниже.

Добавление xml атрибутов

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

В первую очередь нужно создать в папке values файл attrs.xml, где мы сможем определить атрибуты. Для этого view мы добавим один атрибут — template типа string. Выглядеть это будет так:

Мы записали тег declare-styleable и задали имя TemplateTextView. Имя может быть произвольным, но обычно задают имя, совпадающее с именем view. В данном случае я не задаю имя DurationTextView, потому что планирую использовать template атрибут еще в другом view.

Далее мы определили новый атрибут, установив ему имя template и формат string. Помимо string существует множество других форматов, например, Color, Integer, Boolean, Reference и так далее.

Использовать новый атрибут в layout xml можно так.

Обратите внимание, в корневом элементе мы добавляем такую строчку.

xmlns:app= «http://schemas.android.com/apk/res-auto»

Это позволяет нам использовать атрибуты, которые определены в файле attrs.xml, в нашем layout. В данном случае мы задали префикс «app», хотя он может быть произвольным.

Для того чтобы использовать новый атрибут, нужно получить его значение в нашем custom view. Сначала заменяем приватную статическую константу «TEMPLATE» переменной «template». Затем добавляем в наш конструктор следующий код.

В первой строке мы получаем набор атрибутов, который содержит все атрибуты, существующие в xml файле. Метод obtainStyledAttributes() делает две основные вещи. Во-первых, он фильтрует все атрибуты из attrs с помощью контекста, применяет стили и resolves reference to values. Во-вторых, он возвращает только те атрибуты, которые вы определили. Они задаются вторым аргументом, который представляет собой массив ссылок на требуемые атрибуты. В данном случае в R.styleable.TemplateTextView у нас только один атрибут R.attr.template, который мы создали в файле attrs.xml.

Далее мы используем массив attributes, чтобы получить значение атрибута. Если значение шаблона не было определено или не содержит «%s», мы устанавливаем template = «%s». И в заключении нужно не забыть освободить ресурсы с помощью функции recycle().

После некоторых изменений в layout, приложение будет выглядеть так:

Здесь я установил шаблон для первых трех custom view

Большая часть view в Android имеет методы, которые позволяют устанавливать значения XML атрибутов в коде. Возможно вам тоже понадобиться добавить какой-нибудь метод, это зависит от того, как вы будете использовать view.

В следующей части мы посмотрим как нарисовать свой собственное содержимое view компонента и сделаем view для отображения графика.

Исходники к статье можно скачать c GitHub.
По материалам сайта Jayway
Вольный перевод — Pavel Bobkov.

Источник

Темы, стили и атрибуты

В Android существуют стили и темы которые позволяют структурировать разработку пользовательского интерфейса.

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

Пример объявления атрибута из Android SDK:

Ссылка на другой атрибут через @[package:]type/name структуру тоже является типом.

Темы vs стили

Темы и стили очень похожи, но используются для разных целей.

Стиль объединяет атрибуты для конкретного виджета. Извлекая атрибуты в стили, их можно легко использовать и поддерживать в нескольких виджетах одновременно.

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

Стили и темы предназначены для совместной работы.

Например, у нас есть стиль, в котором фон кнопки — colorPrimary , а цвет текста — colorSecondary . Фактические значения этих цветов приведены в теме.

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

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

Виды ссылок в XML

Атрибут android:background может принимать несколько типов:

В случае с @color/colorPrimary — мы cсылаемся на цветовой ресурс colorPrimary , а точнее на #FFFFFF строку, которая прописана в res/values/color.xml файле.

Цвет — это ресурс, на который ссылаются используя значение, указанное в атрибуте «name», а не имя XML-файла. Таким образом, можно комбинировать цветовые ресурсы с другими ресурсами в XML-файле под одним элементом , но я этого не рекомендую.

В свою очередь, ?attr — это ссылка на аттрибут темы.

Читайте также:  Контакты с днями рождения для андроида

?attr/colorPrimary указывает на colorPrimary атрибут, который находится в текущей теме:

Преимущество ?attr ссылок в том, что они будут меняться в зависимости от выбранной темы.

Использование атрибутов темы позволяет создавать меньше стилей, изолируя изменения внутри темы.

Всегда старайтесь ссылаться на цветовые ресурсы через атрибуты темы

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

Структура ссылок

package — (опционально) название пакета, в котором находится ресурс. По умолчанию — это пакет приложения, в котором находится ресурс.

type — может быть одним из color , string , dimen , layout или какого-либо другого типа ресурса. Более подробно читайте здесь.

name — имя ресурса, используется как идентификатор ресурса.

package — (опционально) название пакета, в котором находится ресурс. По умолчанию — это пакет приложения, в котором находится ресурс.

type — (опционально) всегда attr когда используем ? .

name — имя ресурса, используется как идентификатор ресурса.

? vs ?attr vs ?android:attr

Возможно, вы замечали, что к некоторым атрибутам можно обратиться как ?android:attr/colorPrimary , так и ?attr/colorPrimary , а также ?colorPrimary .

Это связано с тем, что некоторые атрибуты определены в Android SDK, и поэтому нужно указывать приставку android , чтобы ссылаться на них.

Мы можем использовать ? и ?attr в случае, когда эти атрибуты находятся в библиотеках(Например, в AppCompat или MaterialDesign), которые компилируюся в приложение, поэтому пространство имен не требуется.

Некоторые элементы определены и в Android SDK, и в библиотеке, например colorPrimary .

В таких случаях лучше использовать версию из библиотеки, поскольку она имеет поддержку на всех уровнях API.

Полезные ссылки

Ниже список с интересными статьями о стилях и темах от Google Android разработчиков:

Источник

Рисование собственных представлений (View) в Android

Получите полный контроль над представлением и оптимизируйте его производительность

В преддверии старта курса «Android Developer. Professional» приглашаем всех желающих принять участие в открытом вебинаре на тему «Пишем gradle plugin».

А пока делимся переводом полезного материала.

Введение

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

В Android доступен широкий набор готовых виджетов и макетов для создания пользовательского интерфейса, однако они не могут удовлетворить все требования наших приложений. И здесь на помощь приходит возможность создания собственных представлений. Создав собственный подкласс представления, можно получить максимально полный контроль за внешним видом и функционалом экранного элемента.

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

Зачем создавать собственные представления?

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

Производительность: в вашем макете много представлений и вы хотите оптимизировать их, нарисовав одно, более легкое собственное представление.

Имеется сложная иерархия представлений, которую трудно использовать и поддерживать.

Необходимо создать специализированное представление, требующее рисования вручную.

Общий подход

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

Создать класс, расширяющий базовый класс или подкласс представления.

Реализовать конструкторы, использующие атрибуты из XML-файла.

Переопределить некоторые методы родительского класса (onDraw(), onMeasure() и т. д.) в соответствии с нашими требованиями.

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

Пример

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

Шаг 1. Создадим класс с именем CircularTextView .

Шаг 2. Расширим класс виджета TextView. Здесь под TextView в IDE выдается ошибка, в которой сообщается, что у этого типа есть конструктор и он должен быть инициализирован.

Шаг 3. Добавим конструкторы в класс.

Это можно сделать двумя способами.

Первый способ добавления конструкторов в класс показан ниже.

Другой способ заключается в добавлении аннотации @JvmOverloads к вызову конструктора, как показано ниже.

Часто нас сбивает с толку то, что у представления есть несколько разных типов конструкторов.

View(Context context)

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

View(Context context, @Nullable AttributeSet attrs)

Конструктор, который вызывается при формировании представления из XML-файла. Он вызывается, когда представление создается из XML-файла, содержащего атрибуты представления. В этом варианте конструктора используется стиль по умолчанию (0), поэтому применяются только те значения атрибутов, которые есть в теме контекста и заданном наборе AttributeSet .

Читайте также:  Андроид удаление не включается

Шаг 4. Самый важный шаг в отрисовке собственного представления — это переопределение метода onDraw() и реализация необходимой логики отрисовки внутри этого метода.

Метод OnDraw (canvas: Canvas?) имеет параметр Canvas (холст), с помощью которого компонент представления может отрисовывать себя. Для рисования на холсте необходимо создать объект Paint.

Как правило, процесс рисования определяется двумя аспектами:

что рисовать (определяется объектом Canvas);

как рисовать (определяется объектом Paint).

Например, Canvas предоставляет метод для рисования линии, а Paint предоставляет методы для определения цвета этой линии. В нашем случае объект Canvas в классе CircularTextView предоставляет метод для рисования окружности, а объект Paint заполняет ее цветом. Проще говоря, Canvas определяет, какие фигуры можно нарисовать на экране, а Paint определяет свойства нарисованных фигур — цвет, стиль, шрифт и т. д.

Давайте займемся кодом. Мы создаем объект Paint и присваиваем ему некоторые свойства, а затем рисуем фигуру на холсте (объект Canvas), используя наш объект Paint. Метод onDraw() будет выглядеть так:

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

При выполнении отрисовки всегда помните о том, что следует повторно использовать объекты вместо создания новых. Ваша IDE может указать на потенциальные проблемы, но полагаться на нее не стоит. Например, она не сможет отследить случай, когда объекты создаются внутри методов, вызываемых из метода onDraw() . Поэтому лучше проверять все самостоятельно.

Шаг 5. Мы закончили с рисованием. Теперь давайте внесем этот класс представления в XML.

Добавьте этот XML-макет в вашу активность (Activity) и запустите приложение. Вот что будет на экране.

Выглядит неплохо, правда? Теперь сделаем так, чтобы значение динамическому свойству цвета в circlePaint назначалось из активности, а также добавим контур к кружку. Для этого в классе CircularTextView необходимо создать несколько методов-сеттеров, чтобы можно было вызывать эти методы и устанавливать свойства динамически.

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

Теперь мы можем устанавливать цвет из нашей активности динамически, вызывая этот метод.

Неплохо, правда? Теперь давайте добавим контур к кружку. Контур будет задаваться двумя входными параметрами: шириной линии контура и ее цветом. Чтобы задать цвет линии контура, нам нужно создать объект Paint точно так же, как мы это делали для кружка. Чтобы задать ширину линии контура, мы создадим переменную, установим для нее нужное значение и используем его в методе onDraw() . Полный код будет выглядеть так:

Теперь в активности можно динамически настраивать эти атрибуты нужным образом.

Далее давайте запустим приложение, устанавливая различные цвета для нашего виджета.

Итак, теперь стало ясно, как динамически устанавливать свойства из активности, но возникает вопрос о том, как устанавливать атрибуты из XML. Продолжим наше исследование.

Для начала создадим файл с именем attrs.xml в папке values. Этот файл будет содержать все атрибуты для различных представлений, которые мы создаем сами. В приведенном ниже примере у нашего представления под названием CircularTextView имеется атрибут ct_circle_fill_color , который принимает значение цвета. Аналогичным образом мы можем добавить и другие атрибуты.

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

Теперь просто переходим к XML-макету и устанавливаем значение свойства, соответствующее нужному цвету, после чего запускаем приложение. На выходе мы увидим нужный результат.

В моем случае результат был таким:

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

Обновление представления

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

invalidate()

invalidate() — это метод, который инициирует принудительную перерисовку определенного представления. Проще говоря, метод invalidate() следует вызывать в случае, когда требуется изменение внешнего вида представления.

requestLayout()

Если в какой-то момент происходит изменение состояния представления, то метод requestLayout() сообщает системе представлений, что необходимо сделать перерасчет фаз «измерение» (Measure) и «макет» (Layout) для данного представления (измерение → макет → рисование). Проще говоря, метод requestLayout() следует вызывать в случае, когда требуется изменение границ представления.

Теперь, я надеюсь, вы знаете в общих чертах, как создавать собственные представления. Чтобы они демонстрировали отличную производительность, необходимо освоить все описанные здесь методы.

Источник

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