he buscado en ya través de toda la web, y no podía encontrar una manera de lograr esto. La respuesta anterior no me ayudó. Encontré todo el método "ArrayAdapter" muy poco intuitivo, inútil y difícil de implementar.
Finalmente, en realidad tuve que buscar dentro del código fuente de "ListPreference", para ver qué hacían allí, y averiguar cómo anular el comportamiento predeterminado de forma limpia y eficiente.
Estoy compartiendo mi solución a continuación. Hice la clase "SelectiveListPreference" para heredar el comportamiento de "ListPreference", pero agregué un botón positivo y evité el cierre cuando se presiona una opción. También hay un nuevo atributo xml para especificar qué opciones están disponibles en la versión gratuita.
Mi truco es no llamar a la versión de onPrepareDialogBuilder de ListPreference, sino implementar la mía, con un controlador de clic personalizado. No tuve que escribir mi propio código para mantener el valor seleccionado, ya que utilicé el código de ListPreference (es por eso que extendí "ListPreference" y no "Preference").
El controlador busca el recurso booleano "free_version" y si es verdadero, solo permite las opciones especificadas en el atributo "entry_values_free" xml. Si "free_version" es falso, todas las opciones están permitidas. También hay un método vacío para herederos, si algo debe suceder cuando se elige una opción.
Enjoy,
Tal
public class SelectiveListPreference extends ListPreference
{
private int mSelectedIndex;
private Collection<CharSequence> mEntryValuesFree;
private Boolean mFreeVersion;
public SelectiveListPreference(Context context)
{
super(context);
}
//CTOR: load members - mEntryValuesFree & mFreeVersion
public SelectiveListPreference(Context context, AttributeSet attrs)
{
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SelectiveListPreference);
try
{
CharSequence[] entryValuesFree = a
.getTextArray(R.styleable.SelectiveListPreference_entryValuesFree);
mEntryValuesFree = new ArrayList<CharSequence>(
Arrays.asList(entryValuesFree));
}
finally
{
a.recycle();
}
Resources resources = context.getResources();
mFreeVersion = resources.getBoolean(R.bool.free_version);
}
//override ListPreference's implementation - make our own dialog with custom click handler, keep the original selected index
@Override
protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder builder)
{
CharSequence[] values = this.getEntries();
mSelectedIndex = this.findIndexOfValue(this.getValue());
builder.setSingleChoiceItems(values, mSelectedIndex, mClickListener)
.setPositiveButton(android.R.string.ok, mClickListener)
.setNegativeButton(android.R.string.cancel, mClickListener);
};
//empty method for inheritors
protected void onChoiceClick(String clickedValue)
{
}
//our click handler
OnClickListener mClickListener = new OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
if (which >= 0)//if which is zero or greater, one of the options was clicked
{
String clickedValue = (String) SelectiveListPreference.this
.getEntryValues()[which]; //get the value
onChoiceClick(clickedValue);
Boolean isEnabled;
if (mFreeVersion) //free version - disable some of the options
{
isEnabled = (mEntryValuesFree != null && mEntryValuesFree
.contains(clickedValue));
}
else //paid version - all options are open
{
isEnabled = true;
}
AlertDialog alertDialog = (AlertDialog) dialog;
Button positiveButton = alertDialog
.getButton(AlertDialog.BUTTON_POSITIVE);
positiveButton.setEnabled(isEnabled);
mSelectedIndex = which;//update current selected index
}
else //if which is a negative number, one of the buttons (positive or negative) was pressed.
{
if (which == DialogInterface.BUTTON_POSITIVE) //if the positive button was pressed, persist the value.
{
SelectiveListPreference.this.setValueIndex(mSelectedIndex);
SelectiveListPreference.this.onClick(dialog,
DialogInterface.BUTTON_POSITIVE);
}
dialog.dismiss(); //close the dialog
}
}
};
}
EDIT: también hay que anular el implementado onDialogClosed de ListPreference (y no hacer nada), de lo contrario, las cosas valiosas no se deje persistido.Agregar:
protected void onDialogClosed(boolean positiveResult) {}
No se puede resolver el método getDialog(). – t0m