26

Hi all I have set the theme in the manifest file like this:

android:theme="@android:style/Theme.Light"

But I have a problem in the Preferences Activity, in the main preferences the theme shows ok, but if I get to a sub preference, the theme gets messy, it is not white as it should, it is all dark, and the font is black so you can't see much, and when I start clicking on any items they will get sometimes white as they should but revert to black soon after. This is only happens on 2.1, in both the real device and emulator. Tested on the emulator running 1.6 and it was working correctly. Here is part of the code of the preferences xml file:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceScreen
        android:title="@string/account">
        <CheckBoxPreference
            android:key="enable_account"
            android:title="@string/account_use"
            android:summary="@string/account_summ" />
        <EditTextPreference
            android:key="username"
            android:title="@string/login"
            android:dependency="enable_account"
            android:summary="@string/login_summ" />
        <EditTextPreference
            android:key="password"
            android:title="@string/password"
            android:dependency="enable_account"
            android:summary="@string/password_summ"
            android:password="true" />
    </PreferenceScreen>

And here is a screenshot:

alt text

Any workarounds?

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Jan S.
  • 10,328
  • 3
  • 31
  • 36
  • Not very helpful maybe but I use the light theme in most of my apps but I leave the preferences in the default black theme because it seems appropriate, my view is users will expect all apps preferences to have the same style. – Jim Blackler Apr 11 '10 at 11:23
  • Great idea! Thanks. Now how can I mark this question answered if the answer was a comment? – Jan S. Apr 11 '10 at 18:01

5 Answers5

15

Somebody just posted a workaround at http://code.google.com/p/android/issues/detail?id=4611

In a nutshell, top level preference screens seem to recognize the theme but nested ones not. So the workaround recommends creating top level PreferenceActivity for nested PreferenceScreen and then invoking this new activity via intent:

<PreferenceScreen android:key="key1"
                      android:title="1 Item"
                      android:summary="">
        <intent android:action="android.intent.action.VIEW"
                android:targetPackage="com.example"
                android:targetClass="com.example.PreferenceActivity2"/>
</PreferenceScreen>

I didn't have to apply the theme to anything but the application itself.

Alex Gitelman
  • 24,429
  • 7
  • 52
  • 49
  • 5
    Check the link in the answer, there is a simpler solution now, see Comment 35 – powder366 Jan 06 '13 at 19:15
  • There's another solution even easier than both of these workarounds; see my answer http://stackoverflow.com/a/25613182/231078. – Joe Sep 01 '14 at 21:40
4

You can also use this technique to override the styles of the inner preference screens :

@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
        Preference preference) {
    super.onPreferenceTreeClick(preferenceScreen, preference);
    if (preference != null) {
        if (preference instanceof PreferenceScreen) {
            if (((PreferenceScreen) preference).getDialog() != null) {
                ((PreferenceScreen) preference)
                        .getDialog()
                        .getWindow()
                        .getDecorView()
                        .setBackgroundDrawable(
                                this
                                .getWindow()
                                .getDecorView()
                                .getBackground()
                                .getConstantState()
                                .newDrawable()
                        );
            }
        }
    }
    return false;
}

This code applies the style of the main preference screen to the clicked preference screen.

Bahadir Tasdemir
  • 10,325
  • 4
  • 49
  • 61
3

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
2

This does appear to be a bug. See http://code.google.com/p/android/issues/detail?id=4611

0

There's an even easier solution, if you're okay with using what seems like black magic to accomplish this...

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 the Context being used in the PreferenceScreen is actually our PreferenceActivity, so all we have to do is override the getThemeResId() method (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)
 */
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