Last active
January 31, 2022 10:49
-
-
Save cardil/4754571 to your computer and use it in GitHub Desktop.
MultiSelectListPreference for devices running Android in the API earlier than level 11. Support ChangeListener receiving list of selected values. Supports automatically setting of summary. Examples attached.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static OnPreferenceChangeListener autoOnChangeListener = new OnPreferenceChangeListener() { | |
@Override | |
public boolean onPreferenceChange(Preference rawPreference, Object newValue) { | |
List<CharSequence> selected = Arrays.asList((CharSequence[]) newValue); | |
if (selected.contains("1")) { | |
// do some work | |
} | |
return true; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package pl.wavesoftware.widget; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Iterator; | |
import java.util.List; | |
import android.app.AlertDialog.Builder; | |
import android.content.Context; | |
import android.content.DialogInterface; | |
import android.content.DialogInterface.OnMultiChoiceClickListener; | |
import android.content.res.TypedArray; | |
import android.preference.ListPreference; | |
import android.util.AttributeSet; | |
public class MultiSelectListPreference extends ListPreference { | |
private String separator; | |
private static final String DEFAULT_SEPARATOR = "\u0001\u0007\u001D\u0007\u0001"; | |
private boolean[] entryChecked; | |
public MultiSelectListPreference(Context context, AttributeSet attributeSet) { | |
super(context, attributeSet); | |
entryChecked = new boolean[getEntries().length]; | |
separator = DEFAULT_SEPARATOR; | |
} | |
public MultiSelectListPreference(Context context) { | |
this(context, null); | |
} | |
@Override | |
protected void onPrepareDialogBuilder(Builder builder) { | |
CharSequence[] entries = getEntries(); | |
CharSequence[] entryValues = getEntryValues(); | |
if (entries == null || entryValues == null | |
|| entries.length != entryValues.length) { | |
throw new IllegalStateException( | |
"MultiSelectListPreference requires an entries array and an entryValues " | |
+ "array which are both the same length"); | |
} | |
restoreCheckedEntries(); | |
OnMultiChoiceClickListener listener = new DialogInterface.OnMultiChoiceClickListener() { | |
public void onClick(DialogInterface dialog, int which, boolean val) { | |
entryChecked[which] = val; | |
} | |
}; | |
builder.setMultiChoiceItems(entries, entryChecked, listener); | |
} | |
private CharSequence[] unpack(CharSequence val) { | |
if (val == null || "".equals(val)) { | |
return new CharSequence[0]; | |
} else { | |
return ((String) val).split(separator); | |
} | |
} | |
/** | |
* Gets the entries values that are selected | |
* | |
* @return the selected entries values | |
*/ | |
public CharSequence[] getCheckedValues() { | |
return unpack(getValue()); | |
} | |
private void restoreCheckedEntries() { | |
CharSequence[] entryValues = getEntryValues(); | |
// Explode the string read in sharedpreferences | |
CharSequence[] vals = unpack(getValue()); | |
if (vals != null) { | |
List<CharSequence> valuesList = Arrays.asList(vals); | |
for (int i = 0; i < entryValues.length; i++) { | |
CharSequence entry = entryValues[i]; | |
entryChecked[i] = valuesList.contains(entry); | |
} | |
} | |
} | |
@Override | |
protected void onDialogClosed(boolean positiveResult) { | |
List<CharSequence> values = new ArrayList<CharSequence>(); | |
CharSequence[] entryValues = getEntryValues(); | |
if (positiveResult && entryValues != null) { | |
for (int i = 0; i < entryValues.length; i++) { | |
if (entryChecked[i] == true) { | |
String val = (String) entryValues[i]; | |
values.add(val); | |
} | |
} | |
String value = join(values, separator); | |
setSummary(prepareSummary(values)); | |
setValueAndEvent(value); | |
} | |
} | |
private void setValueAndEvent(String value) { | |
if (callChangeListener(unpack(value))) { | |
setValue(value); | |
} | |
} | |
private CharSequence prepareSummary(List<CharSequence> joined) { | |
List<String> titles = new ArrayList<String>(); | |
CharSequence[] entryTitle = getEntries(); | |
CharSequence[] entryValues = getEntryValues(); | |
int ix = 0; | |
for (CharSequence value : entryValues) { | |
if (joined.contains(value)) { | |
titles.add((String) entryTitle[ix]); | |
} | |
ix += 1; | |
} | |
return join(titles, ", "); | |
} | |
@Override | |
protected Object onGetDefaultValue(TypedArray typedArray, int index) { | |
return typedArray.getTextArray(index); | |
} | |
@Override | |
protected void onSetInitialValue(boolean restoreValue, | |
Object rawDefaultValue) { | |
String value = null; | |
CharSequence[] defaultValue; | |
if (rawDefaultValue == null) { | |
defaultValue = new CharSequence[0]; | |
} else { | |
defaultValue = (CharSequence[]) rawDefaultValue; | |
} | |
List<CharSequence> joined = Arrays.asList(defaultValue); | |
String joinedDefaultValue = join(joined, separator); | |
if (restoreValue) { | |
value = getPersistedString(joinedDefaultValue); | |
} else { | |
value = joinedDefaultValue; | |
} | |
setSummary(prepareSummary(Arrays.asList(unpack(value)))); | |
setValueAndEvent(value); | |
} | |
/** | |
* Joins array of object to single string by separator | |
* | |
* Credits to kurellajunior on this post | |
* http://snippets.dzone.com/posts/show/91 | |
* | |
* @param iterable | |
* any kind of iterable ex.: <code>["a", "b", "c"]</code> | |
* @param separator | |
* separetes entries ex.: <code>","</code> | |
* @return joined string ex.: <code>"a,b,c"</code> | |
*/ | |
protected static String join(Iterable<?> iterable, String separator) { | |
Iterator<?> oIter; | |
if (iterable == null || (!(oIter = iterable.iterator()).hasNext())) | |
return ""; | |
StringBuilder oBuilder = new StringBuilder(String.valueOf(oIter.next())); | |
while (oIter.hasNext()) | |
oBuilder.append(separator).append(oIter.next()); | |
return oBuilder.toString(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > | |
<pl.wavesoftware.widget.MultiSelectListPreference | |
android:defaultValue="@array/pref_autoon_defaults" | |
android:entries="@array/pref_autoon_titles" | |
android:entryValues="@array/pref_autoon_values" | |
android:key="autoon" | |
android:persistent="true" | |
android:title="@string/pref_autoon_events_title" /> | |
</PreferenceScreen> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<resources> | |
<string-array name="pref_autoon_values"> | |
<item>1</item> | |
<item>2</item> | |
<item>3</item> | |
<item>4</item> | |
</string-array> | |
<string-array name="pref_autoon_titles"> | |
<item>If the phone rings</item> | |
<item>While traveling</item> | |
<item>While charging</item> | |
<item>Periodically checks</item> | |
</string-array> | |
<string-array name="pref_autoon_defaults"> | |
<item>2</item> | |
<item>3</item> | |
</string-array> | |
</resources> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Line 79 produces the following error:
E/InputEventReceiver: Exception dispatching input event.
E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
E/MessageQueue-JNI: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at MyMultiSelectListPreference.restoreCheckedEntries(MyMultiSelectListPreference.java:81)
at MyMultiSelectListPreference.onPrepareDialogBuilder(MyMultiSelectListPreference.java:44)
at android.preference.DialogPreference.showDialog(DialogPreference.java:306)
at android.preference.DialogPreference.onClick(DialogPreference.java:277)
at android.preference.Preference.performClick(Preference.java:994)
at android.preference.PreferenceScreen.onItemClick(PreferenceScreen.java:249)
at android.widget.AdapterView.performItemClick(AdapterView.java:310)