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)
Now one can use the library as easy as putting the following line in the application module's gradle file:
For more info and usage tips, go to the project's page.
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:
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)
<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:
Basically it overrides the built-in
listSeparatorTextViewStyle, which is the style of the preference category's
TextView, to make it better looking.
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: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.
I tested the latest version (23.1.0) of the support library and it fixes the following bugs:
@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.
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:
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.
So, Google gives us a solution which I think is not ideal but works. According to this, instead of using
one should use
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>
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)
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:
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.