2012-03-10 8 views
8

Estoy creando un menú de configuración para una versión gratuita de mi aplicación. Tengo un ListPreference que muestra muchas opciones diferentes. Sin embargo, solo algunas de estas opciones estarán disponibles en la versión gratuita (me gustaría que todas las opciones estén visibles, pero deshabilitadas, ¡así el usuario sabrá qué es lo que están perdiendo!).Desactivar filas en ListPreference

Tengo dificultades para desactivar ciertas filas de mi ListPreference. ¿Alguien sabe cómo se puede lograr esto?

Respuesta

6

Lo resolvió.

Hice una clase personalizada que se extiende ListPreference. Luego usé un ArrayAdapter personalizado y usé los métodos areAllItemsEnabled() y isEnabled(int position).

public class CustomListPreference extends ListPreference { 

    public CustomListPreference (Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 


    protected void onPrepareDialogBuilder(Builder builder) { 
     ListAdapter listAdapter = new CustomArrayAdapter(getContext(), R.layout.listitem, getEntries(), resourceIds, index); 

     builder.setAdapter(listAdapter, this); 
     super.onPrepareDialogBuilder(builder); 
    } 
} 

y

public class CustomArrayAdapter extends ArrayAdapter<CharSequence> { 

public CustomArrayAdapter(Context context, int textViewResourceId, 
     CharSequence[] objects, int[] ids, int i) { 
    super(context, textViewResourceId, objects); 

} 

    public boolean areAllItemsEnabled() { 
     return false; 
    } 

    public boolean isEnabled(int position) { 
     if(position >= 2) 
      return false; 
     else 
      return true; 
    } 

public View getView(int position, View convertView, ViewGroup parent) { 
      ... 
    return row; 
} 
0

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) {} 
0

Tal vez usted puede hacerlo por overrding predeterminado getView:

Pasos:

  1. extienden ListPreference

  2. onPrepareDialogBuilder override y debe sustituirse mBuilder en DialogPreference con ProxyBuilder

  3. getView manija en ProxyBuilder-> AlertDialog-> onShow-> getListView-> Adaptador

Ejemplos de código están en custom row in a listPreference?

0

Que tiene el mismo problema que encontré una solución (tal vez "Hack" es más apropiado) . Podemos registrar un OnPreferenceClickListener para el ListPreference. Dentro de este oyente podemos obtener el diálogo (dado que se hizo clic en la preferencia, estamos bastante seguros de que no es null). Con el cuadro de diálogo podemos establecer un OnHierarchyChangeListener en el ListView del cuadro de diálogo donde se nos notifica cuando se agrega una nueva vista secundaria. Con la vista de niño a mano podemos deshabilitarlo. Suponiendo que las entradas ListView se crean en el mismo orden que los valores de entrada del ListPreference, incluso podemos obtener el valor de entrada.

Espero que alguien encuentre esto útil.

public class SettingsFragment extends PreferenceFragment { 


    private ListPreference devicePreference; 
    private boolean hasNfc; 

    @Override 
    public void onCreate(android.os.Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    // load preferences 
    addPreferencesFromResource(R.xml.preferences); 

    hasNfc = getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC); 

    devicePreference = (ListPreference) getPreferenceScreen().findPreference(getString(R.string.pref_device)); 

    // hack to disable selection of internal NFC device when not available 
    devicePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 

     public boolean onPreferenceClick(Preference preference) { 
      final ListPreference listPref = (ListPreference) preference; 
      ListView listView = ((AlertDialog)listPref.getDialog()).getListView(); 
      listView.setOnHierarchyChangeListener(new OnHierarchyChangeListener() { 

       // assuming list entries are created in the order of the entry values 
       int counter = 0; 

       public void onChildViewRemoved(View parent, View child) {} 

       public void onChildViewAdded(View parent, View child) { 
        String key = listPref.getEntryValues()[counter].toString(); 
        if (key.equals("nfc") && !hasNfc) { 
         child.setEnabled(false); 
        } 
        counter++; 
       } 
      }); 
      return false; 
     } 
    }); 
    } 
} 
+0

No se puede resolver el método getDialog(). – t0m

Cuestiones relacionadas