I have a list of folders I'd like to display in a preference as a list of strings. I'm storing the folders via SharedPreferences.Editor.putStringSet()
. The user can click a row to remove that entry.
I'm not sure how to display the values in a custom Preference
; a ListView would be ideal. The built in preferences don't support this use case and Preference.getPersistedStringSet
is hidden "pending API approval", apparently for years, so a custom Preference won't work easily.
I could use a delimited string with a static helper method within the custom Preference
to ensure a call to SharedPreferences.Editor.putString()
(instead of putStringSet
) is formatted properly, but that's a bit sloppy. Any better ideas?
So I created a custom DialogPreference
as the existing views would have been a poor/confusing user experience. It will actually link to (and requires) a StringSet
preference key and allow the user to remove entries. You could modify the onClick
to have it behave differently.
public class RemovableListPreference extends DialogPreference implements OnClickListener
{
private static final String androidns="http://schemas.android.com/apk/res/android";
private ListView mListView;
private ArrayAdapter<String> mAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1);
private TextView mSplashText,mValueText;
private String mPreferenceKey;
private Context mContext;
private String mDialogMessage;
public RemovableListPreference(Context context, AttributeSet attrs) {
super(context,attrs);
mContext = context;
// Message attribute for the alert dialog
int mDialogMessageId = attrs.getAttributeResourceValue(androidns, "dialogMessage", 0);
if(mDialogMessageId == 0)
mDialogMessage = attrs.getAttributeValue(androidns, "dialogMessage");
else
mDialogMessage = mContext.getString(mDialogMessageId);
// Key attribute for the view, used to automatically update the preferences
int preferenceId = attrs.getAttributeResourceValue(androidns, "key", -1);
if (preferenceId == -1)
throw new RuntimeException(RemovableListPreference.class.getSimpleName() + " requires a preference key (android:key)");
else
mPreferenceKey = mContext.getString(preferenceId);
}
@Override
protected View onCreateDialogView() {
LinearLayout.LayoutParams params;
LinearLayout layout = new LinearLayout(mContext);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setPadding(6,6,6,6);
mSplashText = new TextView(mContext);
if (mDialogMessage != null)
mSplashText.setText(mDialogMessage);
layout.addView(mSplashText);
mValueText = new TextView(mContext);
mValueText.setGravity(Gravity.CENTER_HORIZONTAL);
mValueText.setTextSize(32);
params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
layout.addView(mValueText, params);
mListView = new ListView(mContext);
mListView.setDivider(getDivider());
mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
mAdapter.remove(mAdapter.getItem(position));
}
});
layout.addView(mListView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
return layout;
}
public void setEntries(Set<String> entries)
{
mAdapter.clear();
mAdapter.addAll(entries);
}
@Override
public void showDialog(Bundle state) {
super.showDialog(state);
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(mContext);
Set<String> excludedFolders = pref.getStringSet(mContext.getString(R.string.KEY_EXCLUDED_FOLDERS), new HashSet<String>());
mAdapter.clear();
mAdapter.addAll(excludedFolders);
Button positiveButton = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
positiveButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (mPreferenceKey != null)
{
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
Set<String> rows = new HashSet<>();
for (int i = 0; i < mAdapter.getCount(); ++i)
{
rows.add(mAdapter.getItem(i));
}
editor.putStringSet(mPreferenceKey, rows);
editor.apply();
}
((AlertDialog) getDialog()).dismiss();
}
private Drawable getDivider() {
int[] attrs = { android.R.attr.listDivider };
TypedArray a = mContext.obtainStyledAttributes(attrs);
Drawable divider = a.getDrawable(0);
a.recycle();
return divider;
}
}
Ex. header:
<com.anthonymandra.widget.RemovableListPreference
android:key="@string/KEY_EXCLUDED_FOLDERS"
android:negativeButtonText=""
android:title="@string/excludedFolders"
android:summary="@string/excludedSummary"
android:dialogTitle="@string/excludedFolders"
android:dialogMessage="@string/excludedMessage"/>