Search code examples
androidandroid-themeandroid-styles

How to use specific styles with specific themes?


I'm trying to wrap my head around styles and themes. I currently have a single theme in my app:

<style name="WhiteTheme" parent="Theme.AppCompat.Light.NoActionBar">
    ...
</style>

I also have many styles for different views, like this:

<style name="BodyText" parent="TextAppearance.AppCompat.Body1">
    <item name="android:textSize">14sp</item>
    <item name="android:textColor">@color/default_text_color</item>
</style>

...which I use like this:

<TextView
    ...
    android:textAppearance="@style/BodyText"/>

Now, if I were to create a new theme, say, a DarkTheme, how would I ensure that all the TextViews referencing BodyText as their TextAppearance would point to the new style?


Solution

  • Create an attr for the resource you would like to have different across themes.

    <attr name="someTextColor" format="color"/>
    

    Now in your themes, define the attrs

    <style name="WhiteTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="someTextColor">@android:color/black</item>
    </style>
    
    <style name="DarkTheme" parent="Theme.AppCompat">
        <item name="someTextColor">@android:color/white</item>
    </style>
    

    Now you can use them.

    <style name="BodyText" parent="TextAppearance.AppCompat.Body1">
        <item name="android:textSize">14sp</item>
        <item name="android:textColor">?attr/someTextColor</item>
    </style>
    

    You can also get the attr from code

    /**
     * Returns color for attr from the {@link Theme}
     *
     * @param theme {@link Theme} to get int from
     * @param attr  Attribute of the int
     * @return dimension for attr from the {@link Theme}
     */
    @ColorInt
    public static int getColor(@NonNull final Theme theme, @AttrRes final int attr) {
        final TypedArray array = theme.obtainStyledAttributes(new int[]{attr});
        try {
            return array.getColor(0, Color.TRANSPARENT);
        } finally {
            array.recycle();
        }
    }
    

    Or as ColorStateList

    /**
     * Returns {@link ColorStateList} for attr from the {@link Theme}
     *
     * @param theme {@link Theme} to get int from
     * @param attr  Attribute of the int
     * @return dimension for attr from the {@link Theme}
     */
    @Nullable
    public static ColorStateList getColorStateList(@NonNull final Theme theme,
            @AttrRes final int attr) {
        final TypedArray array = theme.obtainStyledAttributes(new int[]{attr});
        try {
            return array.getColorStateList(0);
        } finally {
            array.recycle();
        }
    }
    

    Then

    final int someTextColor = getColor(getTheme(), R.attr.someTextColor);
    // or
    final ColorStateList someTextColor = getColorStateList(getTheme(), R.attr.someTextColor);