I'm trying to customize a Spinner to be multi-selectable. I have successfully made it multi-selectable, but when an item is reselected, the view inside of the spinner does not get updated.
The Problem
When an item is reselected in the Spinner
, the getView()
of my SpinnerAdapter
gets called, produces the View
that I want it to, but that View
somehow does not get displayed. I have stepped through everything in the debugger and I cannot find any differences between when a different item is selected or the same item is reselected. I have been through all of the code in Spinner
AbsSpinner
and AdapterView
and I cannot find what may be causing this.
For Example
The spinner is populated with 6 items: Choice 1-6. The spinner originates with all items unselected. Choice 1, 2, and 4 are selected. The view inside the spinner displays "Choice 1, Choice 2, Choice 4" correctly.
Choice 4 is unselected (reselection as far as the Spinner is concerned). Choice 4 is correctly unchecked from the list, but the view inside the spinner does not update. It still displays "Choice 1, Choice 2, Choice 4". Stepping through the debugger, getView() on my SpinnerAdapter gets called and everything. For some reason, the View doesn't actually get displayed.
Choice 2 is unselected (this is not a "re-selection" to the Spinner). Here everything functions as expected. Both the list items and the view inside the Spinner are updated.
Some Code
The multi-selectable 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;
}
}
Spinner Adapter
Only posting the important pieces here. Leaving out getters/setters, etc.
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;
}
}
}