Объявление настраиваемых атрибутов в Android - PullRequest
76 голосов
/ 16 мая 2011

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

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

Атрибут 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)?

Ответы [ 2 ]

69 голосов
/ 16 мая 2011

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

А это post .Он содержит полезную информацию о флагах и перечислениях:

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

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

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

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

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

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

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

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

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


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

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

  • логические значения (getAttributeBooleanValue),
  • число с плавающей запятой (getAttributeFloatValue),
  • дюймов (getAttributeIntValue),
  • дюймов (как getAttributeUnsignedIntValue),
  • и строки (getAttributeValue)
63 голосов
/ 12 марта 2014

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

Например, в 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="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>
...