Jak programowo pobrać atrybuty stylu z styles.xml

82

Obecnie używam WebView lub TextView do wyświetlania niektórych danych dynamicznych pochodzących z usługi sieci web w jednej z moich aplikacji. Jeśli dane zawierają czysty tekst, używa TextView i stosuje styl z styles.xml. Jeśli dane zawierają HTML (głównie tekst i obrazy), używa WebView.

Jednak ten WebView nie jest stylizowany. Dlatego wygląda znacznie inaczej niż zwykły TextView. Czytałem, że można stylizować tekst w WebView, po prostu wstawiając kod HTML bezpośrednio do danych. Brzmi to dość łatwo, ale chciałbym użyć danych z mojego Styles.xml jako wartości wymaganych w tym kodzie HTML, więc nie będę musiał zmieniać kolorów i tak dalej w dwóch lokalizacjach, jeśli zmienię style.

Jak więc miałbym to zrobić? Przeprowadziłem obszerne poszukiwania, ale nie znalazłem sposobu na odzyskanie różnych atrybutów stylu z pliku styles.xml. Czy coś mi tu brakuje, czy naprawdę nie można pobrać tych wartości?

Styl, z którego próbuję uzyskać dane, jest następujący:

<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>

Interesuje mnie głównie textSize i textColor.

Sander van't Veer
źródło
Dlaczego po prostu nie przeanalizujesz XML (np. Parser SAX systemu Android)?
m0skit0

Odpowiedzi:

177

Możliwe jest styles.xmlprogramowe pobieranie niestandardowych stylów z .

Zdefiniuj dowolny styl w 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>

Teraz pobierz takie 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
źródło
Świetny kolega z pracy. Po powiedzeniu (i częstym czytaniu), że nie można tego zrobić, doskonale pokazałeś, że można. Właśnie go wypróbowałem i udało mi się uzyskać kolor czcionki z mojego stylu. Nie mogę jeszcze uzyskać tekstu, ale ja to wymyślę. Gdy tylko będę mógł wysłać nagrodę (za 18 godzin), otrzymasz 100 punktów. Wielkie dzięki!
Sander van't Veer
4
czy można również zmienić wartości zdefiniowane w stylu w czasie wykonywania?
ekjyot
A jeśli chcę zmienić kolor pobranych atrybutów? Podoba Ci się dynamiczna zmiana tła lub koloru tekstu w tym kodzie?
MSIslam,
2
Mam problem z tą linią: „TypedArray ta = getStyledAttributes (R.style.MyCustomStyle, attrs);”, Android studio mówi mi, że oczekuje zasobu typu, który można stylizować i nie widzę żadnego sposobu na pominięcie adnotacji w biblioteka wsparcia. Zakładam, że getStyledAttributes ma adnotację @ResStyleable, która uniemożliwia mi przekazywanie stylu jako int. Jakieś pomysły?
Ben Pearson,
1
@BenPearson - Miałem ten sam problem, co podczas próby uzyskania atrybutu textSize. Odpowiedź PrivatMamtora działa i powinna być zaakceptowaną odpowiedzią.
thecoolmacdude
52

Odpowiedź, którą podał @Ole, wydaje się pękać, gdy używasz pewnych atrybutów, takich jak shadowColor, shadowDx, shadowDy, shadowRadius (to tylko kilka, które znalazłem, może być więcej)

Nie mam pojęcia, dlaczego występuje ten problem, o który tutaj pytam , ale styl kodowania @AntoineMarques wydaje się rozwiązać problem.

Aby to działało z dowolnym atrybutem, byłoby to coś takiego


Najpierw zdefiniuj styl, który będzie zawierał identyfikatory zasobów w ten sposób

attrs.xml

<resources>     
    <declare-styleable name="MyStyle" >
        <attr name="android:textColor" />
        <attr name="android:background" />
        <attr name="android:text" />
    </declare-styleable>
</resources>

Następnie w kodzie zrobiłbyś to, aby uzyskać tekst.

TypedArray ta = obtainStyledAttributes(R.style.MyCustomStyle, R.styleable.MyStyle);  
String text = ta.getString(R.styleable.MyStyle_android_text);

Zaletą korzystania z tej metody jest to, że pobierasz wartość według nazwy, a nie indeksu.

PrivatMamtora
źródło
3
To powinna być akceptowana odpowiedź, ponieważ odpowiedź Ole wygenerowała dla mnie ostrzeżenie „oczekiwany zasób typu z możliwością stylizacji”.
thecoolmacdude
1
Działa dla mnie, ale w Android Studio muszę poprzedzić to rozszerzeniem @SuppressWarnings("ResourceType").
eruve
2
Ta odpowiedź powinna być akceptowana. To praca dla wszystkich moich atrybutów, a ta, na którą najczęściej głosowano, zmarnowała mi dużo czasu.
jerry
1
Podziękuj potężnemu delfinowi za rozwiązanie. Zaakceptowana odpowiedź stworzyła dla mnie problemy z atrybutami takimi jak tło (gdy używam rysowania) i rozmiar tekstu. To rozwiązanie działa nie tylko dla wszystkich potrzebnych atrybutów, ale także zapewnia bardziej przejrzysty kod.
Marius P.
2
Czym powinien być R.style.MyCustomStyle?
janosch
1

Odpowiedzi Ole i PrivatMamtora nie działały dobrze, ale tak się stało.

Powiedzmy, że chciałem programowo przeczytać ten styl:

<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>

Mógłbym to zrobić tak:

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()
}

Inspirację zaczerpnąłem z klasy TextAppearanceSpan Androida, którą znajdziesz tutaj: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/text/style/TextAppearanceSpan.java

janosch
źródło
-4

Jeśli zaakceptowane rozwiązanie nie działa, spróbuj zmienić nazwę attr.xml na attrs.xml (działało dla mnie)

Юра Перменко
źródło