Как программно получить атрибуты стиля из styles.xml
В настоящее время я использую либо WebView, либо TextView, чтобы показать некоторые динамические данные, поступающие из веб-сервиса в одном из моих приложений. Если данные содержат чистый текст, он использует TextView и применяет стиль из styles.xml. Если данные содержат HTML (в основном текст и изображения), он использует WebView.
Однако этот WebView не имеет стиля. Для этого он выглядит сильно отличается от обычного TextView. Я читал, что можно стилизовать текст в WebView, просто вставив HTML-код прямо в данные. Это звучит достаточно просто, но я хотел бы использовать данные из моего Styles.xml в качестве значений, требуемых в этом HTML, поэтому мне не нужно будет менять цвета и так далее в двух местах, если я изменю свои стили.
Итак, как я смогу сделать это? Я провел обширный поиск, но не нашел способа на самом деле получить различные атрибуты стиля из вашего styles.xml. Я что-то здесь упускаю или действительно невозможно получить эти значения?
Стиль, из которого я пытаюсь получить данные, следующий:
<style name="font4">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">#E3691B</item>
<item name="android:paddingLeft">5dp</item>
<item name="android:paddingRight">10dp</item>
<item name="android:layout_marginTop">10dp</item>
<item name="android:textStyle">bold</item>
</style>
В основном меня интересуют textSize и textColor.
6 ответов
Можно извлечь пользовательские стили из styles.xml
программно.
Определить произвольный стиль в styles.xml
:
<style name="MyCustomStyle">
<item name="android:textColor">#efefef</item>
<item name="android:background">#ffffff</item>
<item name="android:text">This is my text</item>
</style>
Теперь найдите стили, как это
// The attributes you want retrieved
int[] attrs = {android.R.attr.textColor, android.R.attr.background, android.R.attr.text};
// Parse MyCustomStyle, using Context.obtainStyledAttributes()
TypedArray ta = obtainStyledAttributes(R.style.MyCustomStyle, attrs);
// Fetch the text from your style like this.
String text = ta.getString(2);
// Fetching the colors defined in your style
int textColor = ta.getColor(0, Color.BLACK);
int backgroundColor = ta.getColor(1, Color.BLACK);
// Do some logging to see if we have retrieved correct values
Log.i("Retrieved text:", text);
Log.i("Retrieved textColor as hex:", Integer.toHexString(textColor));
Log.i("Retrieved background as hex:", Integer.toHexString(backgroundColor));
// OH, and don't forget to recycle the TypedArray
ta.recycle()
Ответ, который дал @Ole, кажется, ломается при использовании определенных атрибутов, таких как shadowColor, shadowDx, shadowDy, shadowRadius (я нашел только несколько, их может быть больше)
Я понятия не имею, почему возникает эта проблема, о которой я спрашиваю здесь, но стиль кодирования @AntoineMarques, похоже, решает проблему.
Чтобы это работало с любым атрибутом, было бы что-то вроде этого
Сначала определите стиль, который будет содержать идентификаторы ресурсов, например
attrs.xml
<resources>
<declare-styleable name="MyStyle" >
<attr name="android:textColor" />
<attr name="android:background" />
<attr name="android:text" />
</declare-styleable>
</resources>
Затем в коде вы должны сделать это, чтобы получить текст.
TypedArray ta = obtainStyledAttributes(R.style.MyCustomStyle, R.styleable.MyStyle);
String text = ta.getString(R.styleable.MyStyle_android_text);
Преимущество использования этого метода в том, что вы получаете значение по имени, а не по индексу.
Мне не удалось заставить работать более ранние решения.
Мой стиль:
<style name="Widget.TextView.NumPadKey.Klondike" parent="Widget.TextView.NumPadKey">
<item name="android:textSize">12sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
<item name="android:paddingBottom">0dp</item>
</style>
GetStyledAttributes () для android.R.attr.textSize дает строковые результаты «12sp», которые я затем должен проанализировать. Для android.R.attr.textColor он дал XML-имя файла ресурса. Это было слишком громоздко.
Вместо этого я нашел простой способ использовать ContextThemeWrapper.
TextView sample = new TextView(new ContextThemeWrapper(getContext(), R.style.Widget_TextView_NumPadKey_Klondike), null, 0);
Это дало мне полностью стилизованный TextView для запроса всего, что я хочу. Например:
float textSize = sample.getTextSize();
Ответы от Оле и ПриватМамтора не сработали для меня, но это сработало.
Допустим, я хотел прочитать этот стиль программно:
<style name="Footnote">
<item name="android:fontFamily">@font/some_font</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">@color/black</item>
</style>
Я мог бы сделать это так:
fun getTextColorSizeAndFontFromStyle(
context: Context,
textAppearanceResource: Int // Can be any style in styles.xml like R.style.Footnote
) {
val typedArray = context.obtainStyledAttributes(
textAppearanceResource,
R.styleable.TextAppearance // These are added to your project automatically.
)
val textColor = typedArray.getColorStateList(
R.styleable.TextAppearance_android_textColor
)
val textSize = typedArray.getDimensionPixelSize(
R.styleable.TextAppearance_android_textSize
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val typeface = typedArray.getFont(R.styleable.TextAppearance_android_fontFamily)
// Do something with the typeface...
} else {
val fontFamily = typedArray.getString(R.styleable.TextAppearance_fontFamily)
?: when (typedArray.getInt(R.styleable.TextAppearance_android_typeface, 0)) {
1 -> "sans"
2 -> "serif"
3 -> "monospace"
else -> null
}
// Do something with the fontFamily...
}
typedArray.recycle()
}
Я черпал вдохновение из класса Android TextAppearanceSpan, вы можете найти его здесь: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/text/style/TextAppearanceSpan.java
С Kotlin, если вы включите библиотеку androidx.core:core-ktx в свое приложение / библиотеку ...
implementation("androidx.core:core-ktx:1.6.0") // Note the -ktx
... у вас может быть одно из следующего (вам не нужно перерабатывать TypedArray):
// Your desired attribute IDs
val attributes = intArrayOf(R.attr.myAttr1, R.attr.myAttr2, android.R.attr.text)
context.withStyledAttributes(R.style.MyStyle, attributes) {
val intExample = getInt(R.styleable.MyIntAttrName, 0)
val floatExample = getFloat(R.styleable.MyFloatAttrName, 0f)
val enumExample = R.styleable.MyEnumAttrName, MyEnum.ENUM_1 // See Note 1 below
// Similarly, getColor(), getBoolean(), etc.
}
context.withStyledAttributes(R.style.MyStyle, R.styleable.MyStyleable) {
// Like above
}
// attributeSet is provided to you like in the constructor of a custom view
context.withStyledAttributes(attributeSet, R.styleable.MyStyleable) {
// Like above
}
Примечание 1 (благодаря этому ответу )
Для получения значения перечисления вы можете определить эту функцию расширения:
internal inline fun <reified T : Enum<T>> TypedArray.getEnum(index: Int, default: T) =
getInt(index, -1).let { if (it >= 0) enumValues<T>()[it] else default }
Заметка 2
Разница между зависимостями -ktx, такими как androidx.core: core и androidx.core: core-ktx, заключается в том, что вариант -ktx включает полезные функции расширения для Kotlin. В остальном они такие же.
Также благодаря ответу Оле .
Если принятое решение не работает, попробуйте переименовать attr.xml в attrs.xml (работает для меня)