使用 AndroidX 命名空间自定义 ListPreference 的最简单方法

问题描述 投票:0回答:1

我到处搜索这个问题,发现很多答案无法编译,或者使用已弃用的 API。 这确实是一件简单的事情,我认为不久前就可以将其合并到核心 API 中:

我希望能够单击“首选项”并将单选按钮替换为每行一个 ImageView 和一个 TextView。 就那么简单。 我认为我应该能够将“entries”、“entryValues”和“entryImages”添加到preferences.xml中,并且我认为这会受到支持,因为我在许多其他应用程序中看到了UX。 不敢相信每次都是定制作品。

有人能指出我正确的方向吗?

本文已到此为止,但不完整:首选项屏幕中的自定义列表首选项对话框布局,带有自定义列表项

请帮忙!

我尝试了上面的链接,我可以轻松地打开一个自定义对话框,我只需要创建一个适配器来获取数据,这是我主要拥有的。 我简直不敢相信这么简单的东西需要编码这么多。

java sdk androidx
1个回答
0
投票

对于后代来说,这里的 java 文件可以完成我想要它做的事情。 它引用了 androidx 之前的代码,但适用于 androidx 行为。 它还支持自动将首选项的图标设置为所选图标并更新摘要。

import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.RadioButton;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceManager;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@SuppressWarnings("unused")
public class IconListPreference extends ListPreference {
    private static final int DEFAULT_TINT = 0xFF;
    private static final int DEFAULT_BACKGROUND_TINT = 0xFF;

    private Context mContext;
    private int mErrorResource;
    private final List<Integer> mImages = new ArrayList<>();
    private int mTintColor;
    private int mBackgroundColor;
    private boolean mUseCard;
    private int mCustomItemLayout;
    private String mInitialSummary;

    private class iconListPreferenceAdapter extends ArrayAdapter<ImageListItem> {
        private final List<ImageListItem> mItems;
        private final int mLayoutResource;

        iconListPreferenceAdapter(Context context, int layoutResource, List<ImageListItem> items) {
            super(context, layoutResource, items);
            mLayoutResource = layoutResource;
            mItems = items;
        }

        @NonNull
        @Override
        public View getView(int position, View convertView, @NonNull ViewGroup parent) {
            ViewHolder holder;

            if (convertView == null) {
                LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                try {
                    assert inflater != null;
                    convertView = inflater.inflate(mLayoutResource, parent, false);

                    holder = new ViewHolder();
                    holder.iconName = convertView.findViewById(R.id.iconlistpreference_text);
                    holder.iconImage = convertView.findViewById(R.id.iconlistpreference_image);
                    holder.radioButton = convertView.findViewById(R.id.iconlistpreference_radio);
                    convertView.setTag(holder);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                holder = (ViewHolder)convertView.getTag();
            }

            if (holder == null) {
                return super.getView(position, convertView, parent);
            }

            ImageListItem item = mItems.get(position);

            holder.iconName.setText(item.name);
            if (item.resource != 0) {
                holder.iconImage.setImageResource(item.resource);
            } else {
                holder.iconImage.setImageResource(mErrorResource);
            }
            if (mTintColor != 0) {
                holder.iconImage.setColorFilter(mTintColor);
            }
            if (mBackgroundColor != 0) {
                holder.iconImage.setBackgroundColor(mBackgroundColor);
            }
            holder.radioButton.setChecked(item.isChecked);
            return convertView;
        }
    }

    private static class ImageListItem {
        private final int resource;
        private final boolean isChecked;
        private final String name;

        ImageListItem(CharSequence name, int resource, boolean isChecked) {
            this(name.toString(), resource, isChecked);
        }

        ImageListItem(String name, int resource, boolean isChecked) {
            this.name = name;
            this.resource = resource;
            this.isChecked = isChecked;
        }
    }

    private static class ViewHolder {
        ImageView iconImage;
        TextView iconName;
        RadioButton radioButton;
    }

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

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

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

    public IconListPreference(Context context, AttributeSet attrs, int defStyleAttr,  int defStyleRes) {
        super(context, attrs);

        mContext = context;
        mInitialSummary = Objects.requireNonNull(getSummary()).toString();

        final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.iconlistpreference, defStyleAttr, defStyleRes);

        try {
            int entryImagesArrayResource = array.getResourceId(R.styleable.iconlistpreference_ilp_entryImages, 0);
            String tintKey = array.getNonResourceString(R.styleable.iconlistpreference_ilp_tintKey);
            String backgroundKey = array.getNonResourceString(R.styleable.iconlistpreference_ilp_backgroundTint);

            mTintColor = array.getColor(R.styleable.iconlistpreference_ilp_tint, DEFAULT_TINT);
            mBackgroundColor = array.getColor(R.styleable.iconlistpreference_ilp_backgroundTint, DEFAULT_BACKGROUND_TINT);
            mErrorResource = array.getResourceId(R.styleable.iconlistpreference_ilp_errorImage, 0);
            mUseCard = array.getBoolean(R.styleable.iconlistpreference_ilp_useCard, false);
            mCustomItemLayout = array.getResourceId(R.styleable.iconlistpreference_ilp_itemLayout, 0);
            if (tintKey != null) {
                mTintColor = sharedPreferences.getInt(tintKey, mTintColor);
            }
            if (backgroundKey != null) {
                mBackgroundColor = sharedPreferences.getInt(backgroundKey, mBackgroundColor);
            }
            if (entryImagesArrayResource != 0) {
                TypedArray images = context.getResources().obtainTypedArray(entryImagesArrayResource);

                for (int i = 0; i < images.length(); i++) {
                    mImages.add(images.getResourceId(i, 0));
                }
                images.recycle();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            array.recycle();
        }
    }

    @Override
    protected void onClick() {
        //
        // If an images array has been specified display the custom dialog otherwise
        // display the default.
        //
        if (!mImages.isEmpty()) {
            AlertDialog dialog = onPrepareDialog();

            dialog.show();
        } else {
            super.onClick();
        }
    }

    @Override
    public void setValue(final String value) {
        super.setValue(value);

        int index = findIndexOfValue(value);

        if (index != -1) {
            //
            // Update the icon for the list preference from the list of entryImages, if specified.
            //
            if (!mImages.isEmpty()) {
                setIcon(mImages.get(index));
            }
            //
            // Update the summary.
            //
            if (!mInitialSummary.isEmpty()) {
                setSummary(getEntries()[index] + "\n" + mInitialSummary);
            }
        }
        notifyChanged();
    }

    protected AlertDialog onPrepareDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        List<ImageListItem> items = new ArrayList<>();
        int length = getEntries().length;

        for (int i = 0; i < length; i++) {
            int resource = 0;

            if (mImages.size() > i) {
                resource = mImages.get(i);
            }
            String currentValue = getValue();

            items.add(new ImageListItem(getEntries()[i], resource, (getEntryValues()[i]).equals(currentValue)));
        }

        int layout = R.layout.iconlistpreference_item;

        if (mUseCard) {
            layout = R.layout.iconlistpreference_item_card;
        }
        if (mCustomItemLayout != 0) {
            layout = mCustomItemLayout;
        }

        ListAdapter adapter = new iconListPreferenceAdapter(getContext(), layout, items);

        //
        // Setup the adapter to populate the alertDialog and Set the value that was selected.
        //
        builder.setAdapter(adapter, (dialog, which) -> setValue(getEntryValues()[which].toString()));

        //
        // Cancel the dialog if cancel is pressed.
        //
        builder.setNegativeButton(android.R.string.cancel, null);
        builder.setTitle(getTitle());

        return builder.create();
    }

Only problem is that this code does not render in Android Studio when I try to view the preferences l

布局。 还没明白为什么。

© www.soinside.com 2019 - 2024. All rights reserved.