禁用ListPreference中的行

时间:2012-03-10 02:04:29

标签: android

我正在为我的应用的免费版本创建设置菜单。我有ListPreference显示许多不同的选项。但是,只有部分选项可以在免费版本中使用(我希望所有选项都可见 - 但是已禁用,因此用户知道它们缺少什么!)。

我正在努力禁用ListPreference的某些行。有人知道如何实现这一目标吗?

4 个答案:

答案 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的onPrepareDialogBu​​ilder版本,而是使用自定义点击处理程序实现我自己的版本。我没有编写自己的代码来保存选定的值,因为我使用了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:

来实现

步骤:

  1. 扩展ListPreference

  2. 覆盖onPrepareDialogBu​​ilder并将DialogPreference中的mBuilder替换为ProxyBuilder

  3. 处理ProxyBuilder中的getView-&gt; AlertDialog-&gt; onShow-&gt; getListView-&gt;适配器

  4. 代码示例位于custom row in a listPreference?

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