Sai
Sai

Reputation: 15728

How to change Preference icon color globally Android

I have set flat icon for all my Preference, I would like to change the color of that icon globally.

When I try the below code it even changes the back button color in the toolbar.

I want only Preference icon tint to be changed globally. Thank in advance.

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <SwitchPreference
        android:id="@+id/pref_toggle_alarm"
        android:icon="@drawable/ic_pref_notifications"
        android:key="key_toggle_alarm"
        android:summaryOff="Alarm OFF"
        android:summaryOn="Alarm ON"
        android:title="Alarm" />


    <web.prefs.TimePrefs
        android:id="@+id/pref_select_time"
        android:icon="@drawable/ic_pref_time"
        android:key="key_time"
        android:summary="Set some time"
        android:title="Select Time" />

    <MultiSelectListPreference
        android:id="@+id/pref_select_week"
        android:defaultValue="@array/week_array_values"
        android:entries="@array/array_week_selection"
        android:entryValues="@array/week_array_values"
        android:icon="@drawable/ic_pref_time"
        android:key="key_week"
        android:title="Select Days" />

    <ListPreference
        android:id="@+id/pref_track"
        android:defaultValue="0"
        android:entries="@array/tracks_arrays"
        android:entryValues="@array/tracks_arrays_values"
        android:icon="@drawable/ic_music_note"
        android:key="key_track"
        android:summary="%s"
        android:title="Select Track" />

</PreferenceScreen>

style.xml

<style name="PreferencesTheme" parent="@style/AppTheme.NoActionBar">
    <item name="android:textColorPrimary">@color/primary_text</item>
    <item name="android:textColorSecondary">@color/secondary_text</item>
    <item name="android:colorAccent">@color/accent</item>
    <item name="android:tint">@color/accent</item>
</style>

Upvotes: 9

Views: 5983

Answers (4)

tipapro
tipapro

Reputation: 1

This solution does not change icons tint globally, but also does not cause issues with tint in the toolbar. Invoke this in onViewCreated() of your PreferenceFragmentCompat.

val rv = view.findViewById<RecyclerView>(androidx.preference.R.id.recycler_view)
rv?.viewTreeObserver?.addOnDrawListener {
    rv.children.forEach { pref ->
        val icon = pref.findViewById<View>(android.R.id.icon) as? PreferenceImageView
        icon?.let {
            if (it.tag != "painted") {
                it.setColorFilter(
                    ContextCompat.getColor(requireContext(), R.color.iconColor),
                    PorterDuff.Mode.SRC_IN
                )
                it.tag = "painted"
            }
        }
    }
}

Upvotes: 0

deva56
deva56

Reputation: 15

Old question but still my answer could be valuable to someone. None of the answers above actually worked for me because I didn't want to change the whole theme but just the icon color. If you change the tint color in your reference style and put it into your main theme it will get buggy as it is said in answer above. If you just want to change the icon color and nothing, NOTHING else I highly advise using different drawable resources for day and night scenarious. In my case I have two vector drawables, one for day and one for night theme and they work just fine.

Upvotes: 0

J-Jamet
J-Jamet

Reputation: 857

Here are the solutions that I found after many tests. This implies that you use at least API 21. If you are below, I recommend using a values-v21 folder and a neutral gray color which adapts to black and white backgrounds for default file.

Solution A

One solution, if you use vector icons is to make an attribute to integrate into the XML of each image.

In values/attrs.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="iconPreferenceColor" format="reference|color" />
</resources>

In each icon add android:fillColor="?attr/iconPreferenceColor", sample :

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="?attr/iconPreferenceColor"
        android:pathData="M13,2.05v3.03c3.39,0.49 6,3.39 6,6.92 0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53c0.56,-1.24 0.88,-2.62 0.88,-4.07 0,-5.18 -3.95,-9.45 -9,-9.95zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.53 2.61,-6.43 6,-6.92V2.05c-5.06,0.5 -9,4.76 -9,9.95 0,5.52 4.47,10 9.99,10 3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"/>
</vector>

and in style :

<item name="iconPreferenceColor">@color/green</item>

Solution B (better)

It is possible to tint the icons directly from a style file with PreferenceThemeOverlay.v14.Material.

In values/styles.xml:

<style name="MyStyle.Night" parent="Theme.AppCompat" >
    <item name="preferenceTheme">@style/MyStyle.Preference.v21</item>
    ...
</style>

<!-- Preference Theme -->
<style name="MyStyle.Preference.v21" parent="@style/PreferenceThemeOverlay.v14.Material">
    <item name="android:tint">@color/green</item>
</style>

Please note, you must also use the android:tint parameter in the style of your toolbar, otherwise you may have bugs when changing themes dynamically.

I hope it's helpful

Upvotes: 17

Nicolas
Nicolas

Reputation: 7081

You have to change the color of preference icons programmatically, there's no way to do it by themes or XML attributes. You can add the following in your PreferenceFragment:

@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
    addPreferencesFromResource(R.xml.preferences);

    int colorAttr = android.R.attr.textColorSecondary;

    TypedArray ta = context.getTheme().obtainStyledAttributes(new int[]{colorAttr});
    int iconColor = ta.getColor(0, 0);
    ta.recycle();
    tintIcons(getPreferenceScreen(), iconColor);
}

private static void tintIcons(Preference preference, int color) {
    if (preference instanceof PreferenceGroup) {
        PreferenceGroup group = ((PreferenceGroup) preference);
        for (int i = 0; i < group.getPreferenceCount(); i++) {
            tintIcons(group.getPreference(i), color);
        }
    } else {
        Drawable icon = preference.getIcon();
        if (icon != null) {
            DrawableCompat.setTint(icon, color);
        }
    }
}

Alternatively, I think this library may also be able to help you tint icons. It also fixes other issues with AppCompat preferences.

Upvotes: 7

Related Questions