Disabling strings in ListPreference

I am creating a settings menu for the free version of my application. I have a ListPreference displaying many different options. However, only some of these options should be available in the free version (I would like all the options to be visible, but disabled, so the user knows what they are missing!).

I am trying to disable certain rows of my ListPreference . Does anyone know how this can be achieved?

+8
android
source share
4 answers

I decided.

I made my own class extending ListPreference . Then I used a custom ArrayAdapter and used the areAllItemsEnabled() and isEnabled(int position) methods.

 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); } } 

and

 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; } 
+6
source share

I searched through and across the network, and could not find a way to achieve this. The answer above did not help me. I found the whole ArrayAdapter method very unintuitive, useless, and difficult to implement.

Finally, I really had to look into the source code for the โ€œListPreferenceโ€, see what they did there, and figure out how to undo the default behavior cleanly and efficiently.

I share my decision below. I made the "SelectiveListPreference" class to inherit the "ListPreference" behavior, but added a positive button and did not close when the option was clicked. There is also a new xml attribute to indicate which options are available in the free version.

My trick is not to invoke the ListPreference version for onPrepareDialogBuilder, but instead implement your own using a special click handler. I did not have to write my own code to save the selected value, since I used the ListPreference code (so I expanded the "ListPreference" rather than the "Preference").

The handler looks for the logical resource "free_version", and if it is true, it only allows the parameters specified in the xml_ entry_values_free attribute. If "free_version" is false, all options are allowed. There is also an empty method for inheritors if something should happen when choosing an option.

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 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: we also need to override the implemented onDialogClosed from the ListPreference (and do nothing), otherwise the values โ€‹โ€‹are not saved. Add:

 protected void onDialogClosed(boolean positiveResult) {} 
0
source share

Perhaps you can do this by overriding default getView:

Steps:

  • Extend ListPreference

  • Override onPrepareDialogBuilder and replace mBuilder in DialogPreference with ProxyBuilder

  • Process getView in ProxyBuilder-> AlertDialog-> onShow-> getListView-> Adapter

Are the code samples in a custom line in the list?

0
source share

With the same problem I found a solution (maybe hacking is more suitable). We can register OnPreferenceClickListener for ListPreference . Inside this listener, we can get a dialog (since the click was pressed, we are pretty safe that it is not null ). After the dialog, we can set the OnHierarchyChangeListener to the ListView dialog where we are notified of the addition of a new child view. Given the look at the child, we can turn it off. Assuming the ListView entries are created in the same order as the ListPreference input values, we can even get the value of the entry.

I hope someone finds this helpful.

 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
source share

All Articles