What is the best way to bring Material design to the preferences using AppCompat?
I've been reading some questions and the main points seem to be:
The official guidelines suggest avoiding PreferenceActivity if working for API>11 (and I am). Instead one should use PreferenceFragments;
Using PreferenceActivity would be bad also because you can't extend both PreferenceActivity and ActionBarActivity;
You might use a general ActionBarActivity and load PreferenceFragment (API>11) into it. This way preference widgets loaded from resources gets tinted by AppCompat, but that's not true for any widget (see here );
With the suggested solution, anyway, the whole UI look isn't quite Material (see image on Android 4.2), even if inheriting from AppCompat theme.
Another way could be to extend a PreferenceActivity (API>1). As said, you won't extend ActionBarActivity but just inherit AppCompat theme.
Last, you could just make your own Activity extending ActionBarActivity, and deal with widgets, layouts, margins, SharedPreferences yourself.
At the moment I am not aware of a working solution. I've seen some discussion going on in a Chris Banes post introducing Material, but no solution was suggested. I'm asking:
Did some of you succeed in bringing a pure (as possible) Material look to preferences, and how?
Will there be improvements in v7 regarding this issue in the future?
I'm using AndroidDeveloperLB/MaterialPreferenceLibrary in my projects.
Easy to install. ImportEasy to use. Sample
Related
Given the following:
Android documentation says :
AppCompatActivity - Adds an application activity class that can be used as a base class for activities that use the Support Library action bar implementation.
I'm not considering adding action bar to my activity
I need some material design widgets, which I can control only through AppCompat or material theme, but the latest need API >= 21, which is not my case.
I tested Theme.AppCompat.Light.NoActionBar with Activity class and it works well.
--
Is there an issue with using Activity class with AppCompat theme in my case?
The AppCompat library is intended to make compatibility with olders API, so the Theme and all components may work well in older systems.
I think the only concern is to always use the AppCompat elements and not the regular ones.
Example, use AppCompatEditText, AppCompatTextView, etc... And always refers to they with the AppCompat (AppCompatEditText editText;)
I have used a lot the support library and not have others issues, considering the visual elements may be a little different when using an API minor than 21
No.There is not issues with AppcompactActivity & support libaray. You can refere this link
To gain more rich & amazing look go with support library,Try to do material design
I was trying to implement preferences for an AppCompat app, using support.v7.preference. It took me a couple of days to fiddle through it, since support.v7.preference has some significant differences to the native preferences... which isn't too bad once you know, but unfortunately there's little documentation out there. I thought I'd share my findings so others don't have to go through the same pain.
So... question:
How do you best implement Preferences for AppCompat apps (with PreferenceFragment and AppCompatAcitivity being incompatible)?
Here are a couple of related questions:
Preference sub-screen not opening when using support.v7.preference
How to move back from Preferences subscreen to main screen in PreferenceFragmentCompat?
PreferenceFragmentCompat requires preferenceTheme to be set
How do I create custom preferences using android.support.v7.preference library?
Official docs here:
http://developer.android.com/guide/topics/ui/settings.html
http://developer.android.com/reference/android/support/v7/preference/Preference.html
Solution 1: Native PreferenceFragment with AppCompatActivity
In AndroidStudio, choose File > New Project >...> SettingsActivity. This template uses a workaround that retrofits the native PreferenceFragment to work with AppCompatActivity, similar to the support.v4.Fragment or the support.v7.PreferenceFragmentCompat.
Pro: you can now use the native Preference functionality within an
AppCompat app. It's a quick approach when using the AS template, and you can stick to the existing Preference docs and workflows.
Con: the retrofitting isn't very intuitive or clean. Also since it's usually advisable to use support libs where available, I'm not sure how future-proof this approach is.
Solution 2: support.v7.preference.PreferenceFragmentCompat with AppCompatActivity
Pro: maximizes compatibility
Con: a lot of gaps to bridge. Also this might not work with any of the existing preference-extensions-libs out there (eg. ColorPicker or FontPreferences).
Should you choose not to use Solution 1 (I'm still not sure which of the two is more future proof), there are a couple of drawbacks when using support.v7.preference.
Important drawbacks of using Solution 2 are mentioned below.
Dependencies:
dependencies {
...
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:preference-v7:23.1.1'
compile 'com.android.support:support-v4:23.1.1'
}
Theme:
You'll need to define a preferenceTheme in your styles.xml, otherwise running your app will raise an exception.
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="preferenceTheme">#style/PreferenceThemeOverlay</item>
</style>
You might wanna split this into different styles for 7+/14+/21+. A lot of people complain about this being buggy at the time of this writing. There is a very comprehensive answer available here.
Behavior changes: using the native preferences is extremely straight forward: all you need to do is define/maintain your preferences.xml and use addPreferencesFromResource(R.xml.preferences) within your PreferenceFragment. Custom preferences are easily done by sub-classing DialogPreference, and then just referenced to within the preferences.xml... bam, works.
Unfortunately, support.v7.preference has had everything related to dealing with Fragment stripped out, making it loose a lot of it's built-in functionality. Instead of just maintaining an XML, you now have to sub-class and override a lot of stuff, all of which is unfortunately undocumented.
PreferenceScreens: PreferenceScreens are no longer managed by the framework. Defining a PreferenceScreen in your preference.xml (as described in the docs) will display the entry, but clicking on it does nothing. It's now up to you to deal with displaying and navigating sub-screens. Boring.
There is one approach (described here), adding a PreferenceFragmentCompat.OnPreferenceStartScreenCallback to your PreferenceFragmentCompat. While this approach is quickly implemented, it simply swaps the content of the existing preference fragment. Downside is: there is no back navigation, you're always 'at the top', which isn't very intuitive for the user.
In another approach (described here), you'll also have to manage the back stack in order to achieve back navigation as expected. This uses preferenceScreen.getKey() as a root for each newly created/displayed fragment.
When doing so, you might also stumble over the PreferenceFragments being transparent by default and adding up oddly on top of each other. People tend to override PreferenceFragmentCompat.onViewCreated() to add something like
// Set the default white background in the view so as to avoid transparency
view.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.background_material_light));
Custom DialogPreference: Making your own preferences has also gone from trivial to boring. DialogPreference now has anything that deals with the actual dialog, removed. That bit now lives in PreferenceDialogFragmentCompat. So you'll have to sub-class both, then deal with creating the dialog and displaying it yourself (explained here).
Looking at the source of PreferenceFragmentCompat.onDisplayPreferenceDialog() shows that it knows how to deal with exactly 2 dialog preferences (EditTextPreference, ListPreference), everything else you'll have to implement yourself using OnPreferenceDisplayDialogCallbacks... one wonders, why there is no functionality to handle sub-class of DialogPreference!
Here is some code that implements most of these workarounds and boxes them in a lib module:
https://github.com/mstummer/extended-preferences-compat.git
Main intentions were:
Remove the need to extend and fiddle with Activity and PreferenceFragment in each app/projects. preference.xml is now again the only per-project file to change/maintain.
Handle and display PreferenceScreens (sub-screens) as expected.
Un-split DialogPreference to restore the native behavior.
Handle and display any sub-class of DialogPreference.
Don't think it's clean enough to be just used out of the box, but it might give you some hints when dealing with similar issues. Give it a spin and let me know if you've got any suggestions.
I have an alternative solution to this, that i'd love feedback on.
I made a custom layout for my preferencefragment, with a "Back" button in the upper left corner.
First, in the "onCreatePreference" i store away the root PreferenceScreen:
root = this.getPreferenceScreen();
Then, I add the OnPreferenceStartScreenCallback as described above and in other threads to make the fragment go to subscreen, but in my "onPreferenceStartScreen" i also set the back button to visible like this:
public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) {
preferenceFragmentCompat.setPreferenceScreen(preferenceScreen);
backButton.setVisibility(View.VISIBLE);
return true;
}
Finally, the backButton clickhandler:
setPreferenceScreen(root);
back.setVisibility(View.GONE);
This seem to work fine for me. Obviously the back stack won't work, but i can live with that since there is a Back button.
Not perfect, but given the abysmal API i think i'm happy.
I would love to hear if someone thinks there are any problems with this approach.
Is there an easy way to create a preference like the system preferences in Lollipop?
My previous app had headers and fragments, but I want to use the AppCompat Toolbar and the PreferenceActivity (onBuildHeaders) can't use the new Toolbar. That's why I'm searching for a complete redesign of my preferences.
I want to do this:
Has someone any tutorial for this?
It' s simple. Just apply the Theme.AppCompat.xxx to your activity and put your PreferenceFragment in that activity if you use the Api level >= 11.
EDIT
for the lastest supoort libary appcompat-v7, google provides AppCompatDelegate to do the trick, here is the sample code from google.
Try out my library: https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary .
It lacks some of the stuff of the original API, but it's a good start... The hard part is to make it use a RecyclerView instead of a ListView, so that you could have multiple preferences on the same row. Then you'd need to also filter items as you type.
HoloEverywhere seems to work without extending Sherlock classes. Why do I have to change the imports?
I've just added: android:theme="#style/Holo.Theme.Sherlock"
in the manifest tag and the theme seems to work on the emulator (Android 2.2).
Instructions say:
Extend the Activities from com.WazaBe.HoloEverywhere.sherlock.S***Activity
My Question
Is it a must or an alternative way of applying Holo theme individually?
Does extending the activity from com.WazaBe.HoloEverywhere.sherlock.S***Activity also add ActionbarSherlock to the Activity?
Thanks!
If you want a complete Holo theme port to pre-honeycomb devices, you must extend these classes. If not, some simple controls like EditText or similars will be displayed with holo theme, but others more complex like Dialogs will not be holo-styled.
I am writing my little Android app. I pop up a dialog control which is a nice, non-fullscreen, rounded-corners dialog by setting android:theme="#android:style/Theme.Dialog" on the activity in my manifest. That all works just as I expected. However it is just a drab, grey-titled dialog as in this screenshot:
I've noticed however that a LOT of applications, when they pop up dialogs have a nice, blue-themed title as in this screen shot.
I would assume this theme is some common theme, as it shows up in a LOT of different apps. I would assume it is something built in to the OS. (My phone is a Captivate with the official Froyo release). Of course it COULD be something that every developer simply re-coded on their own, but I doubt that.
Assuming that this is a common theme, how do I utilize it in my app? What changes do I need to make to my activity to have it use that theme?
Thanks in advance!
You can set your activity to use a default theme like Theme.Black. There are default themes and they are in R.style - although i'm not sure which are available to which platforms(i.e. i think the holo themes are for 3.0 and up...
http://developer.android.com/reference/android/R.style.html
see here http://developer.android.com/guide/topics/ui/themes.html for defining your own custom themes and scroll all the way down for using the "platform styles" and themes.
Rather messy (there doesn't seem to be a good reference for this), but the platform styles are defined in \platforms\android-\data\res\values\styles.xml and \platforms\android-\data\res\values\themes.xml. You can dig through those and figure out the theme/style IDs that are available at compile time.
Other than that its really just trial and error.
To make a dialog you need to extend the dialog class. And to have a nice title bar you can use:
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
and have your own custom title.
to have a title use:
setTitle("MyTitle");
You can also assign your custom view for the title.