【发布时间】:2012-03-10 02:04:29
【问题描述】:
我正在为我的应用程序的免费版本创建设置菜单。我有一个 ListPreference 显示许多不同的选项。但是,免费版本中只有其中一些选项可用(我希望所有选项都可见 - 但禁用,以便用户知道他们缺少什么!)。
我正在努力禁用 ListPreference 的某些行。有人知道如何实现吗?
【问题讨论】:
标签: android
我正在为我的应用程序的免费版本创建设置菜单。我有一个 ListPreference 显示许多不同的选项。但是,免费版本中只有其中一些选项可用(我希望所有选项都可见 - 但禁用,以便用户知道他们缺少什么!)。
我正在努力禁用 ListPreference 的某些行。有人知道如何实现吗?
【问题讨论】:
标签: android
解决了。
我创建了一个扩展 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;
}
【讨论】:
我在整个网络上进行了搜索,但找不到实现此目的的方法。上面的答案对我没有帮助。我发现整个“ArrayAdapter”方法非常不直观、无用且难以实施。
最后,我实际上不得不查看“ListPreference”的源代码,看看他们在那里做了什么,并弄清楚如何干净有效地覆盖默认行为。
我在下面分享我的解决方案。我使“SelectiveListPreference”类继承“ListPreference”的行为,但添加了一个肯定按钮,并防止在按下选项时关闭。还有一个新的 xml 属性来指定免费版本中可用的选项。
我的技巧不是调用 ListPreference 的 onPrepareDialogBuilder 版本,而是使用自定义点击处理程序实现我自己的版本。因为我使用了 ListPreference 的代码(这就是我扩展“ListPreference”而不是“Preference”的原因),所以我不必编写自己的代码来保存所选值。
处理程序查找布尔资源“free_version”,如果为真,则仅允许“entry_values_free”xml 属性中指定的选项。如果“free_version”为假,则允许所有选项。如果在选择选项时应该发生某些事情,那么继承者还有一个空方法。
享受,
塔尔
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) {}
【讨论】:
也许你可以通过覆盖默认的 getView 来做到这一点:
步骤:
扩展列表首选项
覆盖 onPrepareDialogBuilder 并将 DialogPreference 中的 mBuilder 替换为 ProxyBuilder
在ProxyBuilder中处理getView->AlertDialog->onShow->getListView->Adapter
【讨论】:
遇到同样的问题,我找到了解决方案(也许“hack”更合适)。我们可以为ListPreference 注册一个OnPreferenceClickListener。在此侦听器中,我们可以得到对话框(因为单击了首选项,所以我们很安全,它不是null)。有了对话框,我们可以在对话框的ListView 上设置OnHierarchyChangeListener,当添加新的子视图时我们会收到通知。使用手头的子视图,我们可以禁用它。
假设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;
}
});
}
}
【讨论】: