新的Preference支持库在运行时不正确的主题

时间:2015-09-08 08:06:08

标签: android android-fragments android-support-library android-preferences preferencefragment

我正在尝试使用新的Preference v14支持库。为了给首选项提供材质样式,我在Activity上使用以下样式:

<style name="PreferenceTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
    <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
</style>

工作正常。我的问题是,当我在运行时添加新的首选项时,它们会使用旧主题进行膨胀。这是结果的屏幕截图:

WTF

如您所见,通过XML添加的第一个首选项具有新的Material样式,而其他首选项不具备。

您对如何解决问题有任何暗示吗?

修改 这是我用来在运行时添加首选项的代码示例:

import android.support.v7.preference.ListPreference;

for (...) {
        final ListPreference p = new ListPreference(getActivity());
        p.setTitle(name);
        p.setSummary(langname);
        p.setEntryValues(langEntryValues);
        p.setEntries(langDisplayValues);
        p.setDialogTitle(R.string.select_language);

        category.addPreference(p);
    }

PS:android.support.v7.preference.Preference

会出现同样的行为

1 个答案:

答案 0 :(得分:17)

您遇到的问题与Context及其主题的运作方式有关。您的代码通过将getActivity()传递给构造函数来检索上下文,但是,这不是您想要的上下文。以下是应用正确样式的解决方案:

final Context ctx = getPreferenceManager().getContext();

for (...) {
    final ListPreference p = new ListPreference(ctx);
    // [...]

    category.addPreference(p);
}

说明

此处PreferenceFragmentCompat的{​​{1}}方法:

onCreate(...)

重要的路线:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    TypedValue tv = new TypedValue();
    this.getActivity().getTheme().resolveAttribute(attr.preferenceTheme, tv, true);
    int theme = tv.resourceId;
    if(theme <= 0) {
        throw new IllegalStateException("Must specify preferenceTheme in theme");
    } else {
        this.mStyledContext = new ContextThemeWrapper(this.getActivity(), theme);
        this.mPreferenceManager = new PreferenceManager(this.mStyledContext);
        // [...]

        this.onCreatePreferences(savedInstanceState, rootKey);
    }
}

此处正在从Activity的主题中检索this.getActivity().getTheme().resolveAttribute(attr.preferenceTheme, tv, true); int theme = tv.resourceId; 。如果它存在(即preferenceTheme不是0), PFC theme)会创建一个新的主题包装器,其中包含样式信息:

PreferenceFragmentCompat

使用此样式化的上下文, PFC 现在可以创建this.mStyledContext = new ContextThemeWrapper(this.getActivity(), theme);

PreferenceManager

PFC root 样式现在是this.mPreferenceManager = new PreferenceManager(this.mStyledContext); ,其中包含所有不同的子样式(例如preferenceTheme )。

您的解决方案的问题是preferenceStyle类在构造函数传递的上下文中查找Preference属性。但是,它仅在preferenceStyle中定义,而不是在活动的主题中定义。