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

Существует очень маленькая документация об declare-styleable теге, с помощью которого мы можем объявлять пользовательские стили для компонентов. Я нашел этот список допустимых значений для атрибута format тега attr . Хотя это хорошо, насколько это возможно, это не объясняет, как использовать некоторые из этих значений. Просмотрев attr.xml (источник Android для стандартных атрибутов), я обнаружил, что вы можете делать такие вещи, как:

 <!-- The most prominent text color. --> <attr name="textColorPrimary" format="reference|color" /> 

Атрибут format очевидно, может быть установлен на комбинацию значений. Предположительно format атрибут format помогает синтаксическому анализатору интерпретировать фактическое значение стиля. Затем я обнаружил это в attr.xml:

 <!-- Default text typeface. --> <attr name="typeface"> <enum name="normal" value="0" /> <enum name="sans" value="1" /> <enum name="serif" value="2" /> <enum name="monospace" value="3" /> </attr> <!-- Default text typeface style. --> <attr name="textStyle"> <flag name="normal" value="0" /> <flag name="bold" value="1" /> <flag name="italic" value="2" /> </attr> 

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

Поэтому у меня есть два вопроса:

  1. В чем разница между атрибутом стиля, который может принимать один из множества значений enum и тот, который может принимать набор значений flag ?
  2. Кто-нибудь знает о какой-либо лучшей документации о том, как declare-styleable (например, обратное проектирование исходного кода Android)?

Solutions Collecting From Web of "Объявление атрибутов стиля в Android"

Здесь есть этот вопрос: определение пользовательских attrs с некоторой информацией, но не много.

И этот пост . Он имеет хорошую информацию о флажках и перечислениях:

Пользовательские флаги атрибутов XML

Флаги являются особыми типами атрибутов, поскольку они допускают только очень небольшое подмножество значений, а именно те, которые определены под тегом атрибута. Флаги определяются атрибутом «name» и атрибутом «value». Имена должны быть уникальными в пределах этого типа атрибута, но значения не обязательно должны быть. Именно по этой причине во время эволюции платформы Android у нас были «fill_parent» и «match_parent», как отображение в одно и то же поведение. Их значения были одинаковыми.

Атрибут name сопоставляется с именем, используемым в месте значения в XML-макете и не требует префикса пространства имен. Следовательно, для «tilingMode» выше я выбрал «center» как значение атрибута. Я мог бы так же легко выбрать «растянутый» или «повторяющийся», но не более того. Даже подмена фактических значений не была бы разрешена.

Атрибут value должен быть целым числом. Выбор шестнадцатеричного или стандартного представления чисел зависит от вас. В коде Android есть несколько мест, в которых оба используются, и компилятор Android тоже рад принять его.

Пользовательские списки атрибутов XML

Перечисления используются почти так же, как флаги с одним условием, они могут быть взаимозаменяемы с целыми числами. Под капотом Enums и Integer сопоставляются с одним и тем же типом данных, а именно с Integer. При появлении в определении атрибута с помощью целых чисел Enums служат для предотвращения «магических чисел», которые всегда плохие. Вот почему вы можете иметь «android: layout_width» с размером, целым числом или с именем «fill_parent».

Предположим, что я создаю настраиваемый атрибут «layout_scroll_height», который принимает либо целое число, либо строку «scroll_to_top». Для этого я бы добавил атрибут формата «целочисленный» и следую за ним с перечислением:

 <attr name="layout_scroll_height" format="integer"> <enum name="scroll_to_top" value="-1"/> </attr> 

Одно из условий при использовании Enums таким образом заключается в том, что разработчик, использующий ваш собственный вид, может целенаправленно поместить значение «-1» в параметры макета. Это вызвало бы специальную логику case «scroll_to_top». Такое неожиданное (или ожидаемое) поведение могло бы быстро отнести вашу библиотеку в кучу «устаревшего кода», если значения Enum были выбраны плохо.


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

Вы можете получить:

  • getAttributeBooleanValue ( getAttributeBooleanValue ),
  • getAttributeFloatValue ( getAttributeFloatValue ),
  • Ints ( getAttributeIntValue ),
  • Ints (как getAttributeUnsignedIntValue ),
  • И строки ( getAttributeValue )

Ответ @Aleadam очень полезен, но imho он опускает одно существенное различие между enum и flag . Первое предназначено для нас, чтобы выбрать одно и только одно значение, когда мы назначаем соответствующий атрибут для некоторого представления. Однако значения последнего могут быть объединены, используя побитовый оператор OR.

Например, в res/values/attr.xml

 <!-- declare myenum attribute --> <attr name="myenum"> <enum name="zero" value="0" /> <enum name="one" value="1" /> <enum name="two" value="2" /> <enum name="three" value="3" /> </attr> <!-- declare myflags attribute --> <attr name="myflags"> <flag name="one" value="1" /> <flag name="two" value="2" /> <flag name="four" value="4" /> <flag name="eight" value="8" /> </attr> <!-- declare our custom widget to be styleable by these attributes --> <declare-styleable name="com.example.MyWidget"> <attr name="myenum" /> <attr name="myflags" /> </declare-styleable> 

В res/layout/mylayout.xml мы можем теперь делать

 <com.example.MyWidget myenum="two" myflags="one|two" ... /> 

Таким образом, перечисление выбирает одно из его возможных значений, а флаги могут комбинироваться. Численные значения должны отражать эту разницу, обычно вам нужно, чтобы последовательность была 0,1,2,3,... для перечислений (для использования в качестве индексов массива, скажем) и флажков, чтобы идти 1,2,4,8,... поэтому они могут быть независимо добавлены или удалены, используя побитовое ИЛИ | Для объединения флагов.

Мы могли бы явно определить «мета-флаги» со значениями, которые не являются степенью 2, и таким образом ввести вид сокращений для общих комбинаций. Например, если бы мы включили это в нашу декларацию myflags

 <flag name="three" value="3" /> 

myflags="three" мы могли бы написать myflags="three" вместо myflags="one|two" , для полностью идентичных результатов, как 3 == 1|2 .

Лично мне нравится всегда включать

 <flag name="none" value="0" /> <!-- or "normal, "regular", and so on --> <flag name="all" value="15" /> <!-- 15 == 1|2|4|8 --> 

Который позволит мне отключить или установить все флаги сразу.

Более тонко, может быть, один флаг подразумевается другим. Итак, в нашем примере предположим, что установленный флаг eight должен принудительно установить four флага (если он еще не был). Затем мы могли бы повторно определить eight чтобы предварительно включить four флага,

 <flag name="eight" value="12" /> <!-- 12 == 8|4 --> 

Наконец, если вы объявляете атрибуты в проекте библиотеки, но хотите применить их в макетах другого проекта (в зависимости от lib), вам нужно использовать префикс пространства имен, который вы должны связать в корневом элементе XML. Например,

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:auto="http://schemas.android.com/apk/res-auto" ... > <com.example.MyWidget auto:myenum="two" auto:myflags="one|two" ... /> </RelativeLayout>