Получить несколько атрибутов стиля с помощью getStyledAttributes

Я пытаюсь получить некоторые из атрибутов стиля пространства имен android из моего кода. Здесь я прилагаю соответствующий экстракт. AttributeSet attrs – это параметр, который передается в любой пользовательский TextView .

 private static final int[] ATTRS = new int[] { android.R.attr.textSize, android.R.attr.text, android.R.attr.textColor, android.R.attr.gravity }; private void processAndroidAttributes(final Context context, final AttributeSet attrs) { final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS); try { final String text = a.getString(1); myTextView.setText(text); final float textSize = a.getDimensionPixelSize(0, DEFAULT_TEXT_SIZE); myTextView.setTextSize(textSize); } 

Моя проблема в том, что я хочу читать 4 атрибута, описанных в int[] ATTRS . Как вы видите, я поместил textSize качестве первого элемента этого массива. Причина этого проста – если я поменял ее на второе место в массиве, ее значение не будет правильно прочитано (вместо этого будет загружено заданное значение по умолчанию). С другой стороны, текст правильно загружается в зависимости от того, какое место в массиве ATTRS я его размещаю. Я не смею экспериментировать с позиционными предпочтениями gravity и textColor , но с этой перестановкой они не работают.

Может ли кто-нибудь объяснить, почему мы наблюдаем поведение получения attrbutes?

Кажется, это ошибка в API. Я тестировал 4 атрибута: gravity , text , textSize и text . Вот код, который я использовал:

 private void processAndroidAttributes(final Context context, final AttributeSet attrs) { ATTRS = new Integer[] { android.R.attr.textSize, android.R.attr.text, android.R.attr.textColor, android.R.attr.gravity }; Arrays.sort(ATTRS); do { printPermutation(ATTRS); tryApplyingStyles(context, attrs, ATTRS); ATTRS = nextPermutation(ATTRS); } while ((ATTRS = nextPermutation(ATTRS)) != null); } 

Метод processAndroidAttributes пытается применить все перечисленные атрибуты и проверять, были ли они применены или использовались значения по умолчанию. Для каждой итерации я ATTRS содержимое массива ATTRS и используется ли реальное значение (с отметкой 1 ) или по умолчанию (помечено 0 ). Вот что я получаю после запуска вышеуказанного кода (каждая итерация печатает пару строк):

 [16842901,16842904,16842927,16843087] 1111 [16842901,16842904,16843087,16842927] 1110 [16842901,16842927,16842904,16843087] 1101 [16842901,16842927,16843087,16842904] 1101 [16842901,16843087,16842904,16842927] 1100 [16842901,16843087,16842927,16842904] 1100 [16842904,16842901,16842927,16843087] 1011 [16842904,16842901,16843087,16842927] 1010 [16842904,16842927,16842901,16843087] 1011 [16842904,16842927,16843087,16842901] 1011 [16842904,16843087,16842901,16842927] 1010 [16842904,16843087,16842927,16842901] 1010 [16842927,16842901,16842904,16843087] 1001 [16842927,16842901,16843087,16842904] 1001 [16842927,16842904,16842901,16843087] 1001 [16842927,16842904,16843087,16842901] 1001 [16842927,16843087,16842901,16842904] 1001 [16842927,16843087,16842904,16842901] 1001 [16843087,16842901,16842904,16842927] 1000 [16843087,16842901,16842927,16842904] 1000 [16843087,16842904,16842901,16842927] 1000 [16843087,16842904,16842927,16842901] 1000 [16843087,16842927,16842901,16842904] 1000 [16843087,16842927,16842904,16842901] 1000 

Как вы видите, это почти похоже на ожидание сортировки массива с несколькими выбросами. Я думаю, что это ошибка в API Android, поскольку документация obtainStyledAttributes не указывает, чтобы ожидать какого-либо упорядочения идентификаторов атрибутов.

У меня такая же проблема, пытаясь получить 4 атрибута с 3 различными типами. Всегда только один тип атрибута переходит к массиву, и это всегда было первым из них. Например, если вы объявляете такие атрибуты, как {int, String, Color}:

 private static final int[] ATTRS = new int[] { android.R.attr.textSize, android.R.attr.text, android.R.attr.textColor } 

Метод obtainStyledAttributes передаст вашему TypedArray только атрибуты int, остальное будет null.

Если вы изменили порядок на {String, Color, int}:

 private static final int[] ATTRS = new int[] {android.R.attr.text, android.R.attr.textColor, android.R.attr.textSize } 

Вы получите только атрибуты String для вашего TypedArray , остальные будут TypedArray .

Похоже, что TypedArray может содержать только один тип, поэтому вам нужно объявить больше TypeArrays – по одному для каждого типа атрибута.

Как это:

 private static final int[] stringAttrs = new int[] {android.R.attr.text}; private static final int[] intAttrs = new int[] {android.R.attr.textSize}; private static final int[] colorAttrs = new int[] {android.R.attr.textColor, android.R.attr.background}; private void processAndroidAttributes(final Context context, final AttributeSet attrs) { final TypedArray stringA = context.obtainStyledAttributes(attrs, stringAttrs); final TypedArray intA = context.obtainStyledAttributes(attrs, intAttrs); final TypedArray colorA = context.obtainStyledAttributes(attrs, colorAttrs); myTextView.setText(stringA.getString(0)); myTextView.setTextSize(intA.getDimensionPixelSize(0, DEFAULT_TEXT_SIZE)); myTextView.setTextColor(colorA.getColor(0, Color.WHITE)); myTextView.setBackgroundColor(colorA.getColor(1, Color.WHITE)); stringA.recycle(); intA.recycle(); colorA.recycle(); } 

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

http://androidxref.com/2.2.3/xref/frameworks/base/core/jni/android_util_AssetManager.cpp#911 Я не смотрел на этот источник близко, но я предполагаю, что андроид выполняет итерацию AttributeSet только один раз в порядке возрастания эффективность.

Я думаю, это может быть потому, что int [], как правило, исходил из xml и сортировался, когда он был «скомпилирован», например, здесь можно проверить вариант использования:

Как определить тему (стиль) для настраиваемого виджета

Где массив поступает из R.styleable.CustomImageButton, а не создается вручную.

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

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

Обратите внимание на 2 вещи:

  1. Int [] значения атрибутов attrs отсортированы по алфавиту
  2. Мы вызываем getStyledAttributes (AttributeSet, int [], int int)

     public static int[] getCommonStyledAttributes() { return new int[] { R.attr.bottom, //0 R.attr.height, //1 R.attr.layout, //2 R.attr.left, //3 R.attr.paddings, //4 R.attr.right, //5 R.attr.top, //6 R.attr.width //7 }; } TypedArray a = context.getTheme().obtainStyledAttributes(paramAttributeSet, getCommonStyledAttributes(), 0, 0); this.mWidth = a.getInt(7, 0); this.mHeight = a.getInt(1, 0); this.left = a.getInt(3, 0); this.top = a.getInt(6, 0); this.right = a.getInt(5, 0); this.bottom = a.getInt(0, 0); this.type = a.getInt(2, 0); a.recycle();