PreferenceActivity and theme not applying

2020-02-08 11:09发布

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?

5条回答
走好不送
2楼-- · 2020-02-08 11:40

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();
        }
查看更多
一夜七次
3楼-- · 2020-02-08 11:41

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.

查看更多
老娘就宠你
4楼-- · 2020-02-08 11:50

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.

查看更多
时光不老,我们不散
5楼-- · 2020-02-08 11:52

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.

查看更多
Ridiculous、
6楼-- · 2020-02-08 11:55
登录 后发表回答