7

I have an activity that extends PreferenceActivity.

My theme : android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" is applied to the application level in the Manifest file.

Everything is getting the desired theme except the "PreferenceScreen" elements of "PreferenceCategory". They are still having the default black background. In simple words, the main Preference Category screen which has the parent Preference Screens are getting the theme but if I click on any of the PreferenceScreens to go to their element preferences(EditText etc etc), they are not getting the theme...

Any Idea why this might be happening?

The structure or preferences.xml is something like this :

<PreferenceCategory>

    <PreferenceScreen>
        <EditTextPreference>
        ...
        </EditTextPreference>
        <EditTextPreference>
        ...
        </EditTextPreference>
        ...
    </PreferenceScreen>

    <PreferenceScreen>
    ...
    </PreferenceScreen>

</PreferenceCategory>
Vikas Singh
  • 1,781
  • 7
  • 27
  • 54

5 Answers5

5

At last i found out how to change theme of "PreferenceActivity" programmatically(via java code)

To change theme just do like this:

        @Override
        public void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.Holo_Theme_Light);
        super.onCreate(savedInstanceState);
        }

Always call setTheme(R.style.yourtheme); method before super.onCreate(savedInstanceState); method. By doing this it will produce result as shown below.

enter image description here

That's all.

If yo call setTheme(R.style.yourtheme); method after super.onCreate(savedInstanceState); method it will produce result as shown below.

enter image description here

Note: Themes are not recognize by nested PreferenceScreen. To apply theme to that nested PreferenceScreen you have to make an another PreferenceActivity for that nested PreferenceScreen and call setTheme(R.style.yourtheme); method there.

E Player Plus
  • 1,836
  • 16
  • 21
3

It's a bug in earlier Android versions (see also http://code.google.com/p/android/issues/detail?id=4611).

If I remember correctly themes aren't properly applied to a PreferenceActivity on all Android 2.x versions. One way to fix this is to set adjust the colors/fonts etc. yourself, but there is also a workaround described in the comments of the bugreport. Themes should work properly on Android 3.0 and later.

THelper
  • 15,333
  • 6
  • 64
  • 104
3

Looking at the source of PreferenceScreen#showDialog(Bundle), we see that the dialog is created using the theme resource obtained via mContext.getThemeResId(), which is then used in a ContextThemeWrapper.

This can help us substantially, because all we have to do is override the getThemeResId() method in your Activity (which is hidden from the public API), to provide our custom theme, and the sub-PreferenceScreen now uses whatever custom theme resource we wanted!

/**
 * This is a hack to provide our own theme for the PreferenceScreen's dialog.
 *
 * @see android.preference.PreferenceScreen#showDialog(Bundle)
 */
// NOTE there is no @Override, even though it overrides the Activity method
public int getThemeResId() {
    return R.style.Theme_MyApp_PreferenceScreen;
}

Note that because this method is annotated with @hide, we can't use the @Override annotation that would normally be used in this case; and we also can't call to the super.getThemeResId() method. If you really, really want to be able to conditionally override this and call through to the super implementation as a fallback, you'll have to use Reflection to get to the super implementation's method:

        try {
            ((Object) this).getClass().getMethod("getThemeResId").invoke(this);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
Joe
  • 42,036
  • 13
  • 45
  • 61
  • 1
    Need to mention that you have to "override" getThemeResId() on your activity. This seems to be the only solution working for nested PreferenceScreen. – Alexey Ozerov Mar 20 '18 at 08:05
2

As all the other answers try to solve it using the java code, this is how I did it completely using xml and without declaring my own preference class.

First I copied the complete layout for a preference from here and changed all the "@+android:id/xyz" to "@android:id/xyz". Then in my styles file, I declared a new style as:

<style name="preference">
    <item name="android:layout">@layout/source_preference</item>
</style>

Now in the AppTheme, a new entry for preference:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:textColor">@drawable/text_selector</item>
    <item name="android:preferenceStyle">@style/preference</item>
</style>

Now for this new layout set all the styles you want. That's it.

psykid
  • 418
  • 5
  • 15
  • Very flexible, thank you. This is a great starting point for anyone looking to customize the PreferenceScreen without rewriting everything from scratch. – Paul T. Jan 10 '19 at 17:25
0
@Override
public boolean onPreferenceTreeClick(final PreferenceScreen preferenceScreen, final Preference preference) {
    // https://code.google.com/p/android/issues/detail?id=4611 comment #35
    if (preference instanceof PreferenceScreen && ((PreferenceScreen) preference).getDialog() != null)
        ((PreferenceScreen) preference).getDialog().getWindow().getDecorView().setBackgroundColor(Color.parseColor("#ffffff"));

    return super.onPreferenceTreeClick(preferenceScreen, preference);
}
Felipe Lima
  • 10,530
  • 4
  • 41
  • 39