当前位置: 首页 > 知识库问答 >
问题:

ListPreference的自定义布局

谭志用
2023-03-14

我正在使用PreferenceActivity设置我的应用程序。我想添加一个新的首选项,允许用户选择一个图标。对于这个任务,我想使用ListPreference,但我也想在列表中显示图标。

我尝试自定义List首选项以使用自定义布局,但问题是一旦我这样做了,列表项就不可单击(它确实显示了我的自定义布局并使用当前选择的默认值)。

我在不同的模拟器版本和银河S2上测试了它。当按下项目时,我可以看到一些按下/未按下的效果,但是onClick方法没有被调用。

我按照Android: Checkable Linear Layout上的说明添加了自定义布局(我还尝试了如何自定义列表首选项单选按钮中描述的选项,但结果相同)。

图标类型首选项.java(从列表首选项复制并修改):

public class IconTypePreference extends DialogPreference {
    private IconType value;
    private int      clickedDialogIndex;
    private boolean  valueSet;

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public IconTypePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public IconTypePreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public IconTypePreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public IconTypePreference(Context context) {
        super(context);
    }

    public void setValue(String value) {
        // Always persist/notify the first time.
        final boolean changed = !TextUtils.equals(getValueText(), value);
        if (changed || !valueSet) {
            if (value == null) {
                this.value = null;
            } else {
                this.value = IconType.valueOf(value);
            }
            valueSet = true;
            persistString(value);
            if (changed) {
                notifyChanged();
            }
        }
    }

    public void setValueIndex(int index) {
        setValue(IconType.values()[index].toString());
    }

    public IconType getValue() {
        return value;
    }

    public String getValueText() {
        return (value == null ? null : value.toString());
    }

    public int findIndexOfValue(String value) {
        IconType[] values = IconType.values();
        for (int i = values.length - 1; i >= 0; i--) {
            if (values[i].toString().equals(value)) {
                return i;
            }
        }
        return -1;
    }

    private int getValueIndex() {
        return findIndexOfValue(getValueText());
    }

    @Override
    protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
        super.onPrepareDialogBuilder(builder);

        clickedDialogIndex = getValueIndex();
        builder.setSingleChoiceItems(new IconTypeAdapter(getContext()), clickedDialogIndex,
                                     new DialogInterface.OnClickListener() {
                                         public void onClick(DialogInterface dialog, int which) {
                                             clickedDialogIndex = which;
                                             IconTypePreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
                                             dialog.dismiss();
                                         }
                                     });
        /*
         * The typical interaction for list-based dialogs is to have
         * click-on-an-item dismiss the dialog instead of the user having to
         * press 'Ok'.
         */
        builder.setPositiveButton(null, null);
    }

    @Override
    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);

        if (positiveResult && clickedDialogIndex >= 0) {
            String value = IconType.values()[clickedDialogIndex].toString();
            if (callChangeListener(value)) {
                setValue(value);
            }
        }
    }

    @Override
    protected Object onGetDefaultValue(TypedArray a, int index) {
        return a.getString(index);
    }

    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        setValue(restoreValue ? getPersistedString(getValueText()) : (String)defaultValue);
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        final Parcelable superState = super.onSaveInstanceState();
        if (isPersistent()) {
            // No need to save instance state since it's persistent
            return superState;
        }

        final SavedState myState = new SavedState(superState);
        myState.value = getValueText();
        return myState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state == null || !state.getClass().equals(SavedState.class)) {
            // Didn't save state for us in onSaveInstanceState
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState myState = (SavedState)state;
        super.onRestoreInstanceState(myState.getSuperState());
        setValue(myState.value);
    }

    private static class SavedState extends BaseSavedState {
        String value;

        public SavedState(Parcel source) {
            super(source);
            value = source.readString();
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeString(value);
        }

        public SavedState(Parcelable superState) {
            super(superState);
        }

        public static final Parcelable.Creator<SavedState> CREATOR =
                new Parcelable.Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }

    private static class IconTypeAdapter extends ArrayAdapter<IconType> {
        private final String[]       iconTypeText;
        private       LayoutInflater inflater;

        public IconTypeAdapter(Context context) {
            super(context, R.layout.icon_type_item, IconType.values());
            this.inflater = LayoutInflater.from(context);
            iconTypeText = context.getResources().getStringArray(R.array.icon_type);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = inflater.inflate(R.layout.icon_type_item, parent, false);
            }
            ((TextView)convertView.findViewById(R.id.text)).setText(iconTypeText[position]);
            convertView.setClickable(true);
            // todo: set view text
            return convertView;
        }

        @Override
        public boolean hasStableIds() {
            return true;
        }

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

CheckableLinearLayout.java

public class CheckableLinearLayout extends LinearLayout implements Checkable {
    private Checkable checkable;

    public CheckableLinearLayout(Context context) {
        super(context);
    }

    public CheckableLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
//        setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
        checkable = getCheckable(this);
        if (checkable == null) {
            throw new RuntimeException("Missing Checkable component");
        }
    }

    private Checkable getCheckable(ViewGroup viewGroup) {
        View v;
        int childCount = viewGroup.getChildCount();
        for (int i = 0; i < childCount; ++i) {
            v = getChildAt(i);
            if (v instanceof Checkable) {
                return (Checkable)v;
            } else if (v instanceof ViewGroup) {
                Checkable result = getCheckable((ViewGroup)v);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

    @Override
    public void setChecked(boolean checked) {
        checkable.setChecked(checked);
    }

    @Override
    public boolean isChecked() {
        return checkable.isChecked();
    }

    @Override
    public void toggle() {
        checkable.toggle();
    }
}

图标_类型_项目. xml

<?xml version="1.0" encoding="utf-8"?>
<com.utils.ui.widget.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                          android:layout_width="match_parent"
                                                          android:layout_height="wrap_content"
                                                          android:orientation="horizontal">
    <TextView android:id="@+id/text"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:focusable="false"
              android:focusableInTouchMode="false"/>
    <RadioButton android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:clickable="false"
                 android:focusable="false"
                 android:focusableInTouchMode="false"/>
</com.utils.ui.widget.CheckableLinearLayout>

添加到settings.xml

<com.utils.ui.preference.IconTypePreference
        android:key="icon_type"
        android:defaultValue="type_b"
        android:title="@string/icon_type_preference_title"/>

编辑

CheckableLinearLayout.java有一个bug

将getCheckable方法替换为:

private Checkable getCheckable(ViewGroup viewGroup) {
    View v;
    int childCount = viewGroup.getChildCount();
    for (int i = 0; i < childCount; ++i) {
        v = viewGroup.getChildAt(i);
        if (v instanceof Checkable) {
            return (Checkable)v;
        } else if (v instanceof ViewGroup) {
            Checkable result = getCheckable((ViewGroup)v);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

共有1个答案

安奇
2023-03-14

找到了解决问题的办法。

适配器的getView方法有问题:我更改了

convertView.setClickable(true);

convertView.setClickable(false);
 类似资料:
  • 有没有办法为不同的日志级别打印不同的布局?例如: 记录器。警告(“消息”);打印如下内容:2016-06-20 13:34:41245 INFO(main:)Message and for logger。信息(“消息2”);仅打印:消息2 有可能做到吗?定义一个布局以警告其他布局以获取信息 log4j.properties

  • 但是,在Log4JV2中,PatternLayout类被设置为“final”,整个体系结构也被更改。似乎不再有一种简单的方法来拦截/覆盖对PatternLayout对象的调用。我查看了Apache文档,但没有太多信息。 我检查了这个问题和这个问题,但都没有太多的帮助。 我意识到这是一个非常“一般”的问题,但是有没有人知道在Log4j V2中实现这一点的简单方法,或者对此有什么建议?

  • 第一次使用JavaFX,所以我对/方法有一个问题。我在做一个弹跳球项目。首先,我使用对象创建球,但由于需要传递更多参数,我决定构建自己的球类()。这是我以前使用时使用的代码: 当将和和放入中时,就会使“球”弹出墙壁。现在,我正试图弄清楚如何使用ball来实现这一点,因为在使用我自己的对象时,无法解析、和方法。如何处理这个/构建自己的等?

  • 问题内容: 我正在尝试使用自己的布局创建DialogFragment。 我见过几种不同的方法。有时,布局是在OnCreateDialog中这样设置的:(我使用的是Mono,但是我已经习惯了Java) 第一种方法对我有用…直到我想使用, 所以在经过一段时间的搜索之后,我尝试了第二种方法,该方法涉及覆盖 因此,我注释掉了设置布局的两行,然后添加了以下内容: 这给了我一个可爱的错误: 我很沮丧 问题答案

  • 我在警报对话框中有一个旋转器。我想减少旋转项之间的填充,因此我实现了以下内容: spinner_row.xml 活动代码包含以下内容: 按照Farrukh的建议,我尝试了他的代码,结果如下。