Как получить необработанное, неразрешенное значение атрибута из AttributeSet? - PullRequest
0 голосов
/ 25 сентября 2018

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

Скажем, был TextView, подобный этому:

<TextView
    ...
    android:textColor="?colorAccent"
    />

Я хочу бытьвозможность извлекать "? colorAccent" в виде строки, или имени записи значения (например, пакет: attr / colorAccent).

Возможно ли это без XMLPullParser?

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Продолжая то, что предоставил @Ben P., я смог придумать что-то, что не использует отражение:

class Attributes(
  private val context: Context,
  private val attrs: AttributeSet
) {
  fun getRawValue(@AttrRes attrId: Int): String {
    val res = context.resources
    val attrName = res.getResourceName(attrId)
    val attrIndex = attrs.indexOfAttr(context) { it == attrName }
    if (attrIndex == -1) return ""
    val attrValue = attrs.getAttributeValue(attrIndex)

    return when {
      attrValue.startsWith('@') || attrValue.startsWith('?') -> {
        val id = attrValue.substring(1)
            .toInt()
        res.getResourceName(id)
      }
      else -> attrValue
    }
  }
}

private fun AttributeSet.indexOfAttr(
  context: Context,
  matcher: (String) -> (Boolean)
): Int {
  for (i in 0 until attributeCount) {
    val nameResource = getAttributeNameResource(i)
    val literalName = if (nameResource != 0) context.resources.getResourceName(nameResource) else ""
    if (matcher(literalName)) {
      return i
    }
  }
  return -1
}

Вот пример использования:

class MyTextView(
  context: Context, 
  attrs: AttributeSet? = null
) : AppCompatTextView() {

  init {
     if (attrs != null) {
         val attributes = Attributes(context, attrs)
         val rawTextColor = attributes.getRawValue(android.R.attr.textColor)
         setText(rawTextColor)
     }
  }
}

Текст текстового представления будет установлен на «необработанное значение» атрибута цвета текста Android, который предоставляется в XML-формате вашего макета.

Если для текста вашего текстового представления задано значение ?colorAccent для AndroidX, приведенный выше код будет заполнятьсяпросмотр текста с текстом [your-package]:attr/colorAccent.Это сделало бы то же самое для ресурса, возвращая полное имя записи, включая пакет.Если бы атрибут был установлен в виде буквального текста, он просто вернул бы это.

0 голосов
/ 25 сентября 2018

Я использую тег представления, который выглядит следующим образом:

<EditText 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:hint="this is the hint"
    android:text="@string/dummy_content"
    android:textColor="?colorAccent" />

Что примечательно в этом, так это то, что android:hint представляет собой простой текст, android:text является атрибутом ресурса и android:textColor - это атрибут стиля.

Для всех трех я начинаю с AttributeSet.getAttributeValue().Для атрибутов простого текста это даст вам фактическое значение (например, для android:hint это возвращает "this is the hint").

Атрибуты ресурса вместо этого возвращают строку, которая начинается с @ и затем является числом (например, для android:text это возвращает "@2131689506").Затем вы можете проанализировать числовую часть этой строки и использовать Resources.getResourceName(), чтобы получить разрешенное имя ("com.example.stackoverflow:string/dummy_content").

Атрибуты стиля возвращают строку, которая начинается с ? и затем является числом (например,для android:textColor это возвращает "?2130903135").Однако я не знаю ни одного способа преобразования этого числа в текстовое представление с помощью поддерживаемых API.Надеюсь, однако, что этого достаточно, чтобы помочь кому-то еще на пути к полному ответу.

Использование отражения

Если вы хотите сойти с рельсов, вы можете использовать отражениенайти текстовое значение атрибута стиля.Поскольку строка начинается с ?, вы знаете, что она либо в R.attr, либо в android.R.attr.Вы можете отсканировать их для поиска подходящего поля с кодом, подобным следующему:

private static String scan(Class<?> classToSearch, int target) {
    for (Field field : classToSearch.getDeclaredFields()) {
        try {
            int fieldValue = (int) field.get(null);

            if (fieldValue == target) {
                return field.getName();
            }
        } catch (IllegalAccessException e) {
           // TODO
        }
    }

    return null;
}
int id = Integer.parseInt(attributeValue.substring(1));
String attrName = scan(R.attr.class, id);
String androidAttrName = scan(android.R.attr.class, id);

Для меня это выдаст

colorAccent
null

Если значениеandroid:textColor было бы ?android:colorAccent вместо просто ?colorAccent, вместо этого было бы вывод:

null
colorAccent
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...