Android:更改微调器项而不关闭微调器

时间:2017-02-22 10:55:13

标签: android android-spinner android-adapter

我正在尝试为微调器实现“更多”按钮。基本上我想首先只显示几个项目,当用户点击最后一项(“更多...”)时,微调器将更改并显示所有项目。

因此,我需要的功能是一种动态更改微调器项而无需关闭微调器的方法。除了最后一部分,我已经成功完成了所有工作。每次我更改项目时,微调器都会自动关闭(不会失去焦点)。

我认为唯一的解决方法是使用Cell_Style在关闭后立即打开微调器。当然,这还不够好,因为我得到了这种快速的重新开启效果。不酷。

我创建了一个管理逻辑的自定义微调器类:

mSpinner.performClick()

和自定义适配器:

public class ReservationStatusSpinner extends Spinner {
    // --------------------------------------------------
    // State
    // --------------------------------------------------
    private final String mMoreStatus;

    private OnItemSelectedListener mUserListener;
    private ArrayAdapter<String> mAdapter;
    private boolean mOpenInitiated = false;

    // --------------------------------------------------
    // Interfaces
    // --------------------------------------------------
    private interface OnSpinnerEventsListener {
        // Not needed, but may be needed in the future -> void onSpinnerOpened();
        void onSpinnerClosed();
    }
    private OnSpinnerEventsListener mOnSpinnerEventsListener;

    public interface OnStatusSelectedListener {
        void onStatusSelected(String status);
    }
    private OnStatusSelectedListener mOnStatusSelectedListener;

    // --------------------------------------------------
    // Construction/Initialization
    // --------------------------------------------------
    public ReservationStatusSpinner(Context context) {
        super(context);
        mMoreStatus = getContext().getResources().getString(R.string.status_more);
        init();
    }

    public ReservationStatusSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
        mMoreStatus = getContext().getResources().getString(R.string.status_more);
        init();
    }

    private void init() {
        // Add listener
        super.setOnItemSelectedListener(new OnItemSelected());

        mOnSpinnerEventsListener = new OnSpinnerEventsListener() {
            @Override
            public void onSpinnerClosed() {
                filterAndSelect();
            }
        };
    }

    // --------------------------------------------------
    // Overridden methods
    // --------------------------------------------------
    @Override
    public boolean performClick() {
        // register that the Spinner was opened so we have a status
        // indicator for the activity(which may lose focus for some other
        // reasons)
        mOpenInitiated = true;
        return super.performClick();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        // mSpin is our custom Spinner
        if (mOpenInitiated && hasFocus) {
            performClosedEvent();
        }
    }

    @Override
    public void setOnItemSelectedListener(OnItemSelectedListener l) {
        mUserListener = l;
    }

    // --------------------------------------------------
    // Private methods
    // --------------------------------------------------
    private static ArrayList<String> getAllStatuses(Context context) {
        ArrayList<String> items = new ArrayList<>();
        CharSequence[] statusesCSArray = context.getResources().getTextArray(R.array.reservation_status);
        for (CharSequence cs : statusesCSArray)
            items.add(cs.toString());
        return items;
    }

    private void performClosedEvent() {
        mOpenInitiated = false;
        if (mOnSpinnerEventsListener != null) {
            mOnSpinnerEventsListener.onSpinnerClosed();
        }
    }

    private void filterAndSelect() {
        List<String> items = filterStatuses((String)getSelectedItem(), mMoreStatus);
        setItems(items);
        setSelection(0);
    }

    // --------------------------------------------------
    // Public methods
    // --------------------------------------------------
    public void setStatus(String status) {
        // Find status in adapter
        int pos = -1;
        for (int i = 0; i < mAdapter.getCount(); ++i) {
            if (mAdapter.getItem(i).equals(status)) {
                pos = i;
                break;
            }
        }

        if (pos != -1)
            setSelection(pos);
    }

    public void setAdapter(ArrayAdapter<String> adapter) {
        super.setAdapter(adapter);
        mAdapter = adapter;
    }

    public void setOnStatusSelectedListener(OnStatusSelectedListener l) {
        mOnStatusSelectedListener = l;
    }

    public void setItems(List<String> items) {
        mAdapter.clear();
        mAdapter.addAll(items);
        mAdapter.notifyDataSetChanged();
    }

    // --------------------------------------------------
    // Utilities
    // --------------------------------------------------
    public static ArrayList<String> filterStatuses(String selectedStatus, String moreStatus) {
        ArrayList<String> list = new ArrayList<>(DataUtilities.filterStatuses(selectedStatus));

        // Add selected status at start
        list.add(0, selectedStatus);

        // Append "More"
        list.add(moreStatus);

        return list;
    }

    // --------------------------------------------------
    // Custom ItemSelectedListener for ReservationStatusSpinner
    // --------------------------------------------------
    private class OnItemSelected implements OnItemSelectedListener {

        private String mPreviousStatus;
        private boolean mMoreClicked = false;

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            String more = getContext().getResources().getString(R.string.status_more);
            String status = getSelectedItem().toString();

            ArrayList<String> items = new ArrayList<>();
            if (status.equals(more)) {
                items.addAll(getAllStatuses(getContext()));
                items.remove(mMoreStatus);
                setItems(items);
                //setStatus(mPreviousStatus);
                mMoreClicked = true;

                // Reopen spinner (it closes after changing data) (TODO: Fix this)
                ReservationStatusSpinner.this.performClick();
            } else if (!mMoreClicked) {
                filterAndSelect();
            }

            if (!status.equals(more)) {
                if (mUserListener != null)
                    mUserListener.onItemSelected(parent, view, position, id);

                if (mOnStatusSelectedListener != null)
                    mOnStatusSelectedListener.onStatusSelected(status);
            }

            mPreviousStatus = status;
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            if (mUserListener != null)
                mUserListener.onNothingSelected(parent);
        }
    }
}

在我的Spinner中,大部分工作都是在代码段末尾的public class ImageSpinnerAdapter extends ArrayAdapter<String> { private LayoutInflater mInflater; public ImageSpinnerAdapter(Context context, int textViewResourceId, List<String> titles) { super(context, textViewResourceId, titles); mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { View view; if (convertView == null) { view = mInflater.inflate(R.layout.row_image_spinner_dropdown, parent, false); } else { view = convertView; } ImageView icon = (ImageView)view.findViewById(R.id.spinner_icon); setIcon(icon, getItem(position)); TextView text = (TextView)view.findViewById(R.id.spinner_status_text); text.setText(DataUtilities.addWhitespacesToStatus(getItem(position))); view.setPadding(0, 0, 0, 0); return view; } @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { View view; if (convertView == null) { view = mInflater.inflate(R.layout.row_image_spinner_view, parent, false); } else { view = convertView; } // Set icon ImageView icon = (ImageView)view.findViewById(R.id.spinner_icon); setIcon(icon, getItem(position)); view.setPadding(0, 0, 0, 0); return view; } private void setIcon(ImageView icon, String status) { // Make sure there are no whitespaces in status status = DataUtilities.removeWhitespaceFromStatus(status); // Get the correct image for each status icon.setImageResource(DataUtilities.statusToIconResource(status)); } } 完成的。

起初我认为问题是我的适配器上的转换视图(我最初没有使用转换视图模式),但正如您所看到的,我现在正在使用它。

问题出现在2个不同的设备和我的模拟器上,因此可以安全地假设它不是特定于设备的问题。

任何人有任何想法或任何指示?

2 个答案:

答案 0 :(得分:1)

您必须使用MultiSelectListview和更多按钮创建自定义对话框。单击更多按钮,您必须将所有元素添加到Listview并调用notifyDataSetChanged()方法。

答案 1 :(得分:1)

默认Spinner无法简单地加载“更多”项。但“更多”按钮没有任何意义。如果你有30-50个项目,只需加载到Spinner。对于50-150项,使用自己的基于ListBox / RecyclerView的Spinner。如果超过150项用户太难搜索必要的一项。在最后一种情况下,添加“搜索”功能很有用。 有关提示,请参阅MultiSelect Spinner

enter image description here