Intrications Intrications - 6 months ago 130
Android Question

PreferenceFragmentCompat requires preferenceTheme to be set

With the new PreferenceFragmentCompat from the v7 Preference Support Library: http://developer.android.com/tools/support-library/features.html#v7-preference, I get this error

E java.lang.IllegalStateException: Must specify preferenceTheme in theme
E at android.support.v7.preference.PreferenceFragmentCompat.onCreate(PreferenceFragmentCompat.java:202)


What theme should be set?

Update: I have tried using

<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>


as suggested by @Bogato but it doesn't look right and looks very Holo even on Lollipop.

Support library:

enter image description here

Native preferences:

enter image description here

Answer

The sample project can be found here

NEW! The bugfix is available as a gradle dependency

Now one can use the library as easy as putting the following line in the application module's gradle file:

compile 'com.takisoft.fix:preference-v7:23.4.0.3'

For more info and usage tips, go to the project's page.


Solution to make the lib work on API 7+ while keeping material theme on API 14+ (v23.4.0 - May 2016)

First of all, create a separate styles.xml for devices 7+ and another one for 14+ (and probably you can create for 21+, etc.).

The v14 (and up) will still use the v14 material themed preference theme (@style/PreferenceThemeOverlay.v14.Material) with the method shown above.

For the v7, we have to set the preference theme to the original one:

<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>

This way the normal (actually a little materialized) preference theme will be used on devices 7-13 and the material one on devices 14 and up. Since the v14 lib requires the min SDK to be set to 14 or higher, we have to use an Android Studio recommended hack: we will override the library's requirements. To do this, you have to add the following line to your manifest:

<uses-sdk xmlns:tools="http://schemas.android.com/tools"
    tools:overrideLibrary="android.support.v14.preference" />

Now the build will succeed. If you check the design on a 7+ device, you'll probably see that the preference categories' design looks really bad. To fix this, include the following lines in your default (or v7, whichever you chose) styles.xml:

<style name="Theme.MyTheme.ListSeparatorTextView">
    <item name="android:textSize">14sp</item>
    <item name="android:textStyle">bold</item>
    <item name="android:textColor">@color/accent</item>
    <item name="android:paddingTop">16dp</item>
    <item name="android:layout_marginBottom">16dp</item>
</style>

Then apply the just created style to your main theme by adding the following line to it:

<item name="android:listSeparatorTextViewStyle">@style/Theme.MyTheme.ListSeparatorTextView</item>

Basically it overrides the built-in listSeparatorTextViewStyle, which is the style of the preference category's TextView, to make it better looking.

That's it, now you can use the support lib on API 7+ without sacrificing the material styles on devices on or above level 14.

There are some bugs(?) though:

  • The whole preference list has a left-right padding which could be removed by effectively overriding all the preference layouts with custom ones that contain the padding inside the layouts instead of applying it on the list itself.
    • The text sizes (especially the titles') look too big. To overcome this, you can override the android:textAppearanceLarge (titles) and android:textAppearanceSmall (summaries) in your theme file but if you do so, you might make other parts of your app look bad, so test it thoroughly.

UPDATE October 18th, 2015

I tested the latest version (23.1.0) of the support library and it fixes the following bugs:

  • background selector is now set
  • the list dialog's wrong-side-of-radio-buttons bug (didn't mention this myself as it was not really annoying, just against the material guidelines)
  • preference titles aren't oversized anymore

The normal @style/PreferenceThemeOverlay isn't materialized yet, so you still have to use the v14 one.

Google removed more of the EditText related methods but my fix still works, though a little update had to be made to the custom classes, so make sure you update those when changing to 23.1.0.

UPDATE September 6th, 2015

Besides the bugs (and temporary fixes) discovered yesterday, here's another one: PreferenceThemeOverlay.v14.Material has no correct background selector. To overcome this, you should add the following line to your main theme style:

<item name="android:activatedBackgroundIndicator">?android:attr/selectableItemBackground</item>

Note that I did not test it extensively so it might mess up other parts of your app. This is just a temporary (i.e. experimental) bugfix until Google releases either a less buggy version of the lib or the source code so we could fix it.

UPDATE September 5th, 2015

So, Google gives us a solution which I think is not ideal but works. According to this, instead of using

<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>

one should use

<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>

This also means that even though you are using only v7, you have to include the v14 lib as well because the said PreferenceThemeOverlay.v14.Material is only available in it.

Another bug is that on API levels below 21 the PreferenceCategory elements' text color is not the accent color you define in your style. To set it to your accent color, you have to define a preference_fallback_accent_color color value in any of your resources files. Example:

<resources>
    <color name="accent">#FF4081</color>
    <!-- this is needed as preference_category_material layout is using this color as the text color -->
    <color name="preference_fallback_accent_color">@color/accent</color>
</resources>

There's a workaround that allows one to use multiple themes and completely avoid overriding preference_fallback_accent_color. Check out the project's repo if you need this fix.

And another bug is that the PreferenceCategory's text style is italic instead of bold. In order to fix this, you have to re-define a so-called Preference_TextAppearanceMaterialBody2 style (this is used by the PreferenceCategory below API level 21) in any of your styles file:

<style name="Preference_TextAppearanceMaterialBody2">
    <item name="android:textSize">14sp</item>
    <item name="android:fontFamily">sans-serif-medium</item>
    <item name="android:textStyle">bold</item>
    <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>

UPDATE September 2015

The issue is still NOT fixed in the latest support library, revision 23.0.1, even though the changelog says this:

Changes for v7 and v14 Preference Support library:

  • Added the material design layout and style files. (Issue 183376)

UPDATE: temporary bugfix until Google fixes it

So, I put together a sample project with the customized style and layout files. You can find it here: https://github.com/Gericop/Android-Support-Preference-V7-Fix

The reported issue is here: https://code.google.com/p/android/issues/detail?id=183376 (seems like the guys are working on it).

Tested on API level 21 and 17. These work now:

  • PreferenceCategory
  • Preference
  • PreferenceCheckbox
  • PreferenceSwitchCompat
  • PreferenceEditText (though I couldn't change the color of the dialog's buttons)
  • PreferenceList (cannot change the color)

In action: enter image description here

Original answer

I made a whole new style for it:

<style name="Theme.MyTheme" parent="@style/Theme.AppCompat.NoActionBar">
    <item name="preferenceTheme">@style/Theme.WtfPreference</item>
    <!-- [...] -->
</style>

<style name="Theme.WtfPreference" parent="@style/PreferenceThemeOverlay">
    <item name="preferenceScreenStyle">@style/Preference.PreferenceScreen</item>
    <item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
    <item name="preferenceCategoryStyle">@style/Preference.Category</item>
    <item name="preferenceStyle">@style/Preference</item>
    <item name="preferenceInformationStyle">@style/Preference.Information</item>
    <item name="checkBoxPreferenceStyle">@style/Preference.CheckBoxPreference</item>
    <item name="switchPreferenceCompatStyle">@style/Preference.SwitchPreferenceCompat</item>
    <item name="dialogPreferenceStyle">@style/Preference.DialogPreference</item>
    <item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference</item>
    <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList</item>
</style>

The reason I call it "WtfPreference" is that if you copy this into your style.xml (or whatever you call it), you can CTRL + click on all the @style/Preference[...] things and you'll see that those values probably refer to the default values folder (cannot confirm as the Android Studio won't follow the next links in the exploded .aar file), hence the Wtf part. I think Google messed something up with the styles, they also haven't released any sample / tutorial for it and the support PreferenceFragmentCompat page shows the same sample as the native one (except for the links), telling nothing about the required preferenceTheme attribute and linking to the 'old' settings guide which refers back to the native classes, not the support ones.

Comments