我正在为我的应用的免费版本创建设置菜单。我有ListPreference
显示许多不同的选项。但是,只有部分选项可以在免费版本中使用(我希望所有选项都可见 - 但是已禁用,因此用户知道它们缺少什么!)。
我正在努力禁用ListPreference
的某些行。有人知道如何实现这一目标吗?
答案 0 :(得分:6)
解决了它。
我制作了一个扩展ListPreference
的自定义类。然后,我使用了自定义ArrayAdapter
并使用了方法areAllItemsEnabled()
和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);
}
}
和
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;
}
答案 1 :(得分:0)
我在整个网络上搜索并找不到实现这一目标的方法。上面的答案对我没有帮助。我发现整个“ArrayAdapter”方法非常不直观,无用且难以实现。
最后,我实际上必须查看“ListPreference”的源代码,看看他们在那里做了什么,并弄清楚如何干净有效地覆盖默认行为。
我在下面分享我的解决方案。我使用“SelectiveListPreference”类来继承“ListPreference”的行为,但添加了一个肯定按钮,并在按下某个选项时阻止关闭。还有一个新的xml属性,用于指定免费版本中可用的选项。
我的诀窍不是调用ListPreference的onPrepareDialogBuilder版本,而是使用自定义点击处理程序实现我自己的版本。我没有编写自己的代码来保存选定的值,因为我使用了ListPreference的代码(这就是为什么我扩展了“ListPreference”而不是“Preference”)。
处理程序查找布尔资源“free_version”,如果是,则只允许“entry_values_free”xml属性中指定的选项。如果“free_version”为false,则允许所有选项。如果在选择选项时会发生某些事情,那么继承者也有一个空方法。
享受,
塔尔
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
}
}
};
}
编辑:我们还需要覆盖从ListPreference中实现的onDialogClosed(并且什么都不做),否则,有价值的东西不会被持久化。添加:
protected void onDialogClosed(boolean positiveResult) {}
答案 2 :(得分:0)
也许你可以通过覆盖默认的getView:
来实现步骤:
扩展ListPreference
覆盖onPrepareDialogBuilder并将DialogPreference中的mBuilder替换为ProxyBuilder
处理ProxyBuilder中的getView-&gt; AlertDialog-&gt; onShow-&gt; getListView-&gt;适配器
答案 3 :(得分:0)
遇到同样的问题我找到了解决方案(也许&#34; hack&#34;更合适)。我们可以为OnPreferenceClickListener
注册ListPreference
。在这个监听器中我们可以得到对话框(因为点击了偏好,我们非常安全,它不是null
)。有了对话框,我们可以在对话框的OnHierarchyChangeListener
上设置ListView
,在添加新的子视图时我们会收到通知。有了孩子视图,我们可以禁用它。
假设ListView
条目的创建顺序与ListPreference
的条目值相同,我们甚至可以获得条目值。
我希望有人觉得这很有帮助。
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;
}
});
}
}