Strangely, the Android framework does not include a widget which allows multiple selections in Preference Screens. I needed to add one of these for selecting folders to monitor for new media in PicPush and ended up having to implement it myself. If this is something you need for your Android app, following this tutorial will have you up and running in under 5 minutes.
Source code with example XML files can be downloaded from here.
Thanks to Mathieu Chauvinc for implementing XML attributes for separator and a check all option!
Step 1: Declare stylable attributes for check all and separator characters in attr.xml
A special XML attribute can be used to define which (if any) is the “Check all” button using the yournamespace:checkAll attribute in the preferences.xml.
A special XML attribute can be used to define the separator value you wish to use (for when the references are stored to disk on the device). Using yournamespace:separator the you can create their own choice of separator (without this the code will fall back to default)
In order to make use of the custom attributes in the layout XML file you must declare them as styleable in attr.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="ListPreferenceMultiSelect"> <attr format="string" name="checkAll" /> <attr format="string" name="separator" /> </declare-styleable> </resources>
Step 2: Declare a multi-choice preference widget in your preferences XML file
The first step involves adding the appropriate XML to the file where your preference screen is defined. This can be done as so (You’ll have to change the undefined references to real @string constants):
<com.threefiftynice.android.preference.ListPreferenceMultiSelect android:defaultValue="#ALL#" android:dependency="@string/pref_auto_scan_image" android:key="@string/pref_upload_buckets_image" android:title="Image folders to monitor" android:dialogTitle="Image folders to monitor" android:summary="Specify which folders should be monitored for images" android:entries="@array/pref_upload_buckets_default_entries" android:entryValues="@array/pref_upload_buckets_default_values"/>
Step 3: Declare supporting resources for the preferences attributes in
The preferences.xml file is referencing some string and array constants which we need to define in other resources
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="pref_upload_buckets_image">upload.buckets_image</string> </resources>
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="pref_upload_buckets_default_entries"> <item>All</item> <item>Test1 Display</item> <item>Test2 Display</item> </string-array> <string-array name="pref_upload_buckets_default_values"> <item>#ALL#</item> <item>Test1 Value</item> <item>Test2 Value</item> </string-array> </resources>
Step 4: Create Java class which implements the Multiple Choice List Preference
Now, of course, we need a Java class to back this up. The implementation is straightforward. It extends the ListPreference widget so it can inherit all the XML attributes recognized by it. From there, a few key methods are overridden which are explained below.
Step 4.1: Override onPrepareDialogBuilder (line 44)
onPrepareDialogBuilder is the method responsible for creating the popup dialog which contains all the choices to be displayed. The change from the base class here is simply to set the multi choice entries of the builder rather than the single choice entries. This takes care of the UI.
Step 4.2: Override onDialogClosed (line 69)
When the dialog is closed we need to build a special string to store in the SharedPreferences. The string is made up of the selected entries separated by a special separator string. The separator string i chose is quite weird, it has to be, to avoid conflicts with actual entries.
Step 4.3: Provide a static convenience method for parsing the stored value into a String array (line 62)
When a client reads back the stored value from the SharedPreferences it wont be very useful unless it can be parsed. This can be delegated to our custom implementation via a static method called parseStoredValue. This convenience method returns a String array which contains the user’s choices.
Step 5: You’re Done! Run the code!
Following the above steps should have you in good shape to get up and running. I implemented this code a few days ago, and am writing this tutorial from memory so i may have missed a few small details, however the main bones of the implementation is definitely contained here. Any problems/questions? Leave a comment below.