6

我正在尝试将 Spinner 自定义为多选。我已成功使其成为多选,但是当重新选择一个项目时,微调器内部的视图不会更新。

问题

当在 中重新选择一个项目时SpinnergetView()SpinnerAdapter的 被调用,产生View我想要的,但View不知何故不会显示。我已经逐步完成了调试器中的所有内容,我找不到选择不同项目或重新选择相同项目之间的任何差异。我已经浏览了所有代码,Spinner AbsSpinnerAdapterView我找不到可能导致这种情况的原因。

例如

微调器包含 6 个项目:选项 1-6。微调器起源于所有未选择的项目。 选择了选项 1、2 和 4。微调器内的视图正确显示“Choice 1, Choice 2, Choice 4”。

选项 4 未选中(就 Spinner 而言,重新选择)。选项 4 已从列表中正确取消选中,但微调器内的视图不会更新。 它仍然显示 "Choice 1, Choice 2, Choice 4"。通过调试器,我的 SpinnerAdapter 上的 getView() 被调用,一切都被调用。由于某种原因,视图实际上并没有显示出来。

选项2 未选中(这不是 Spinner 的“重新选择”)。在这里,一切都按预期运行。Spinner 内的列表项和视图都会更新。

一些代码

多选微调器

public class MultiSelectSpinner extends Spinner {

    private OnItemSelectedListener listener;

    public MultiSelectSpinner(Context context) {

        super( context );
    }

    public MultiSelectSpinner(Context context, AttributeSet attrs) {

        super( context, attrs );
    }

    public MultiSelectSpinner(Context context, AttributeSet attrs, int defStyle) {

        super( context, attrs, defStyle );
    }

    @Override
    public void setSelection( int position ) {

        super.setSelection( position );
        if ( listener != null ) {

            listener.onItemSelected( this, getSelectedView(), position, getAdapter().getItemId( position ) );
        }
    }

    public void setOnItemSelectedEvenIfUnchangedListener( OnItemSelectedListener listener ) {

        this.listener = listener;
    }
}

微调适配器

只在这里发布重要的部分。省略 getter/setter 等。

public class FormChoiceSpinnerAdapter implements SpinnerAdapter, OnItemSelectedListener {

    private Choice[] choices;
    private String title;
    private final DataSetObservable dataSetObservable = new DataSetObservable();

    public FormChoiceSpinnerAdapter(String[] choices, String title) {

        setChoices( new Choice[choices.length] );
        for (int i = 0; i < choices.length; i++) {

            getChoices()[i] = new Choice( choices[i] );
        }
    }

    @Override
    public View getView( int position, View convertView, ViewGroup parent ) {

        Context context = parent.getContext();
        if ( convertView == null ) {

            convertView = LayoutInflater.from( context ).inflate( android.R.layout.simple_spinner_item, parent, false );
        }

        String displayString = "";

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

            Choice choice = getChoices()[i];

            if ( choice.isSelected() ) {

                displayString += choice.getLabel() + ", ";
            }
        }

        if ( displayString.length() > 0 ) {

            displayString = displayString.trim().substring( 0, displayString.length() - 2 );
        }
        else {

            displayString = getTitle() + "...";
        }

        ( (TextView) convertView ).setText( displayString );

        return convertView;
    }

    @Override
    public View getDropDownView( int position, View convertView, ViewGroup parent ) {

        Context context = parent.getContext();
        if ( convertView == null ) {

            convertView = LayoutInflater.from( context ).inflate( R.layout.simple_dropdown_item, parent, false );
        }

        Choice choice = getChoices()[position];
        TextView text = (TextView) convertView.findViewById( android.R.id.text1 );
        text.setText( choice.getLabel() );

        ImageView selectedImage = (ImageView) convertView.findViewById( R.id.image_selected );
        int visibility = choice.isSelected() ? View.VISIBLE : View.GONE;
        selectedImage.setVisibility( visibility );

        return convertView;
    }

    @Override
    public void onItemSelected( AdapterView<?> parent, View view, int position, long id ) {

        Choice choice = getChoices()[position];

        choice.setSelected( !choice.isSelected() );

        ImageView imageView = (ImageView) view.findViewById( R.id.image_selected );

        if ( imageView != null ) {
            imageView.setVisibility( choice.isSelected() ? View.VISIBLE : View.GONE );
        }    
    }

    @Override
    public void onNothingSelected( AdapterView<?> parent ) {

        //No op
    }

    public static class Choice {

        private boolean selected;
        private String label;

        public Choice(String label) {

            this.label = label;
            selected = false;
        }
    }
}
4

2 回答 2

1

我知道这已经很晚了,但我找到了解决我遇到的类似问题的方法。尝试添加adapter.notifyDataSetChanged()到您的onItemSelected(AdapterView<?> parent, View view, int pos, long id)Override 方法。

我的微调器应该显示默认消息,直到用户实际从中选择一个值。除非用户选择下拉列表中的第一项,否则它工作正常,然后微调器不会自行更新。添加adapter.notifyDataSetChanged()工作。

我还查看了一些源代码,但我无法准确找到发生了什么,但我有一个想法。由于在选择已选择的值时Spinner不会调用(除非您扩展,我在此 SO 答案的帮助下完成了此操作),我的猜测是,如果您尝试取消选择最近选择的值,则不会将其视为取消选择,因此不会重绘视图。对您来说,按该顺序选择 1、2、4,然后尝试取消选择 4 不会触发重绘响应,但随后取消选择 2 会导致重绘。OnItemSelectedListenerSpinnerSpinner

我可能是错的,但我知道我们的问题是相似的,这对我有用。

于 2014-02-05T18:28:08.660 回答
0

您需要从 UI 线程更新视图。从另一个与您的问题类似的问题中查看此答案,该问题详细说明了使用 AsyncTask 更新 UI 线程:

https://stackoverflow.com/a/4370785/793150

我有同样的问题,视图不更新片段,我相信这个解决方案也适用于这个问题。

我希望这能解决您的问题!

于 2013-06-21T22:21:33.300 回答