Master On/Off Preferences with Ice Cream Sandwich

Written by Xavier Gouchet - 27 june 2012 - 5 comments

One of the easiest thing to do with android is storing user preferences. It can be as simple as a single xml files and a few lines of code. Since the first version of Android, you have access to several common preference widgets, such as checkboxes, text fields, or even lists.

In Android ICS, new widgets were introduced, among which the SwitchPreference, looking a lot like the iOS famous SwitchButton. If you have paid attention to the Android Design website, you have noticed that Google encourages you to use a Master On/Off switch in the way they used it with the Wifi Preference screen. Here's a reminder for those of you without an ICS device.

Android's Wifi Settings master On/Off Switch

The Wifi can be enabled from the first screen, using the Switch widget. And when you press the Wifi row, you land on the Wifi Preferences screen, where you can select a Wifi Network. At the top of the second screen, you still have a Switch widget to turn the Wifi off if you need to.

Now the question is : how did they do it ? Moreover, how can I do the same in my own preferences ? This is what we're gonna learn in this article. In a fictive video game, here's the preference screens we wan't to see. I'll limit the article to those two screens, others can be done easily after that. This code will only work with API level 14 or higher, so if you're targeting lower devices, be carefull and keep an old fashioned preference screen

The main preferences screen The sound preferences screen

For this article, I dug into the source code of Android's Settings application, so most of this is from Google. The probleme can be divided in two parts. First having the Switch widget at the top of the screen in the second screenshot. This is simply done by using a Switch view in the Custom View of the ActionBar. Then, there is the trickier part of having a preference linking to the second screen and having a Switch widget. You can usually have one or the other, using a PreferenceScreen or a SwitchPreference tag in your xml file. Here, we'll use the Header class introduce in ICS, with a custom adapter (basically almost like having a custom ListView, but with predefined behavior).

To create these screens, we need severall files, so instead of copy pasting all the code in here, I bundled a sample project available for download here.

Here's a list of the files you'll find in the archive, and a little description of what they do :

my_prefs_headers.xml
this file describes the headers of the first screen, meaning each row which links to another PreferenceScreen. Each header can have a title of course, an icon, an id, and a fragment class, defining the PreferenceFragment which will be loaded to display the PreferenceScreen.
MyPrefsActivity.java
the main PreferenceActivity, which loads first our headers, then will load a fragment when a header is clicked.
MyPrefsHeaderAdapter.java
this is the ArraAdapter which will load the Layouts we want for our headers. If you've already worked with ListViews, this should look familiar. This adapter uses 3 different layouts, one for categories sections, one for common header and one for switch header. The "magic" happens in the getHeaderType() method, in which we define which layout should be used with each header.
SoundEnabler.java
this class is mostly a utility we use to bind a Switch widget with the corresponding shared preference. It is linked with the switch defined in the ArrayAdapter described above.
SoundsPreferencesFragment.java
a PreferenceFragment which is used by our Sound header. Nothing much goes here, we mostly load the PreferenceScreen description from an XML file. Also, as described earlier, we create a Switch widget which we had to the ActionBar, and link it to a SoundEnabler instance.

Now, you have a preference screen with a Switch widget, and what's nice is that this trick can work with any other widget than a switch. You just need to create the layout, add it in the Array Adapter and Voila ! If you have any question on this article, please contact me

Download the sample code

5 comments

Hey ,this is great sample ,pretty straightforward but It's not working on tablet it crashes with strange NullPointerException of name == null.. Can you help me fix this I cannot make any sense of this error smile

#1 Written by : Heavylama (saturday 10 november 2012 @ 11:16)

@Heavylama : Hi, could you send me a sample project, as well as the stack trace of your error at android@xgouchet.fr ?

I had the same problem, I tracked some of it down to
<header android:title="Game Options" /> in the preference headers (I believe this is a bug) and also explicitly setting the theme to something with an actionbar (minsdkversion without max or target causes some sort of glitch in themes)

#3 Written by : simon (friday 23 november 2012 @ 19:52)

try adding
@Override
public void switchToHeader(Header header) {
if(header.fragment != null){
super.switchToHeader(header);
}
}

to MyPrefsActivity .... (PreferenceActivity changes behavior for tablet layouts)

#4 Written by : simon (friday 23 november 2012 @ 21:45)

Didn't compile without changes, crashes when clicking a header that is not a master on/off-switch

Galaxy S3, Android 4.1.2

#5 Written by : Drasive (friday 27 september 2013 @ 15:32)

Write a comment

Capcha
Enter image code :