简体   繁体   中英

Selected item not changed in the custom ListPreference

It seems setChecked is invoked every time I click the preference and the selected item changes but in the dialog the selected item remains unchanged for some reason. I have no idea what's going on. Relaunching the application can make the selected item change but that's not the expected behavior. :~

Here's the class:

public class IconListPreference extends ListPreference {
    private Context mContext;
    private LayoutInflater mInflater;
    private Drawable[] mEntryIcons = null;
    private String mKey;
    private int selectedEntry = -1;

    public IconListPreference(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public IconListPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs);
        mContext = context;
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IconPreference, defStyle, 0);
        int entryIconsResId = a.getResourceId(R.styleable.IconPreference_entryIcons, -1);
        if (entryIconsResId != -1) setEntryIcons(entryIconsResId);
        mInflater = LayoutInflater.from(context);
        mKey = getKey();
        a.recycle();
    }

    public void setEntryIcons(Drawable[] entryIcons) {
        mEntryIcons = entryIcons;
    }

    public void setEntryIcons(int entryIconsResId) {
        TypedArray icons_array = mContext.getResources().obtainTypedArray(entryIconsResId);
        Drawable[] icon_ids_array = new Drawable[icons_array.length()];
        for (int i = 0; i < icons_array.length(); i++) icon_ids_array[i] = icons_array.getDrawable(i);
        setEntryIcons(icon_ids_array);
        icons_array.recycle();
    }

    @Override
    protected void onPrepareDialogBuilder(Builder builder) {
        CharSequence[] entries = getEntries(), entryValues = getEntryValues();
        if (entries.length != entryValues.length) throw new IllegalStateException
                ("ListPreference requires an entries array and an entryValues array which are both the same length");
        if (mEntryIcons != null && entries.length != mEntryIcons.length) throw new IllegalStateException
                ("IconListPreference requires the icons entries array be the same length than entries or null");
        IconListPreferenceScreenAdapter iconListPreferenceAdapter = new IconListPreferenceScreenAdapter();
        if (mEntryIcons != null) {
            String selectedValue = getPreferenceManager().getSharedPreferences().getString(mKey, "");
            for (int i = 0; i < entryValues.length; i++) {
                if (selectedValue.compareTo((String) entryValues[i]) == 0) {
                    selectedEntry = i;
                    break;
                }
            }
            builder.setAdapter(iconListPreferenceAdapter, null);
        }
        super.onPrepareDialogBuilder(builder);
    }

    private class IconListPreferenceScreenAdapter extends BaseAdapter {
        public int getCount() {
            return mEntryIcons.length;
        }

        class CustomHolder {
            private CheckedTextView text = null;

            CustomHolder(View row, int position) {
                text = (CheckedTextView) row.findViewById(android.R.id.text1);
                text.setText(getEntries()[position]);
                text.setChecked(selectedEntry == position);
                if (mEntryIcons != null)
                    text.setCompoundDrawablesWithIntrinsicBounds(mEntryIcons[position], null, null, null);
            }
        }

        public Object getItem(int position) {
            return getEntries()[position];
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) convertView = mInflater.inflate(Resources.getSystem()
                            .getIdentifier("select_dialog_singlechoice_holo", "layout", "android"), parent, false);
            CustomHolder holder;
            final int p = position;
            holder = new CustomHolder(convertView, position);
            convertView.setTag(holder);
            convertView.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    v.requestFocus();
                    getDialog().dismiss();
                    IconListPreference.this.callChangeListener(getEntryValues()[p]);
                    SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
                    editor.putString(mKey, getEntryValues()[p].toString());
                    selectedEntry = p;
                    editor.apply();
                }
            });
            return convertView;
        }
    }
}

And res/values/attrs.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="IconPreference">
        <attr name="entryIcons" format="reference" />
    </declare-styleable>
</resources>

EDIT: Updated my code with a bugfix, but still don't work sthough. A temporary solution found: invoke setValue((String) newValue) in OnPreferenceChangeListener.onPreferenceChange .

OK I finally get it. You need to do the following to make your customized preference work:

  • callChangeListener before setting user-supplied values;
  • notifyChanged if you need to update user interface, ie whenever value changes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM