How to use Android Spinner like a drop-down list How to use Android Spinner like a drop-down list android android

How to use Android Spinner like a drop-down list


+1 to David's answer. However, here's an implementation suggestion that does not involve copy-pasting code from the source (which, by the way, looks exactly the same as David posted in 2.3 as well):

@Overridevoid setSelectionInt(int position, boolean animate) {    mOldSelectedPosition = INVALID_POSITION;    super.setSelectionInt(position, animate);}

This way you'll trick the parent method into thinking it's a new position every time.

Alternatively, you could try setting the position to invalid when the spinner is clicked and setting it back in onNothingSelected. This is not as nice, because the user will not see what item is selected while the dialog is up.


Ok, I think I've come up with a solution for my own situation with the help of both David's and Felix' answer (I believe David's helped Felix', which in turn helped mine). I thought I'd post it here together with a code sample in case someone else finds this approach useful as well. It also solves both of my problems (both the unwanted automatic selection and the desired re-selection trigger).

What I've done is added a "please select" dummy item as the first item in my list (initially just to get around the automatic selection problem so that I could ignore when it was selected without user interaction), and then, when another item is selected and I've handled the selection, I simply reset the spinner to the dummy item (which gets ignored). Come to think of it, I should've thought of this long ago before deciding to post my question on this site, but things are always more obvious in hindsight... and I found that writing my question actually helped me to think about what I wanted to achieve.

Obviously, if having a dummy item doesn't fit your situation, this might not be the ideal solution for you, but since what I wanted was to trigger an action when the user selected a value (and having the value remain selected is not required in my specific case), this works just fine. I'll try to add a simplified code example (may not compile as is, I've ripped out a few bits from my working code and renamed things before pasting, but hopefully you'll get the idea) below.

First, the list activity (in my case) containing the spinner, let's call it MyListActivity:

public class MyListActivity extends ListActivity {    private Spinner mySpinner;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // TODO: other code as required...        mySpinner = (Spinner) findViewById(R.id.mySpinner);        mySpinner.setAdapter(new MySpinnerAdapter(this));        mySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {            @Override            public void onItemSelected(AdapterView<?> aParentView,                        View aView, int aPosition, long anId) {                if (aPosition == 0) {                    Log.d(getClass().getName(), "Ignoring selection of dummy list item...");                } else {                    Log.d(getClass().getName(), "Handling selection of actual list item...");                    // TODO: insert code to handle selection                    resetSelection();                }            }            @Override            public void onNothingSelected(AdapterView<?> anAdapterView) {                // do nothing            }        });    }    /**     * Reset the filter spinner selection to 0 - which is ignored in     * onItemSelected() - so that a subsequent selection of another item is     * triggered, regardless of whether it's the same item that was selected     * previously.     */    protected void resetSelection() {        Log.d(getClass().getName(), "Resetting selection to 0 (i.e. 'please select' item).");        mySpinner.setSelection(0);    }}

And the spinner adapter code could look something like this (could in fact be an inner class in the above list activity if you prefer):

public class MySpinnerAdapter extends BaseAdapter implements SpinnerAdapter {    private List<MyListItem> items; // replace MyListItem with your model object type    private Context context;    public MySpinnerAdapter(Context aContext) {        context = aContext;        items = new ArrayList<MyListItem>();        items.add(null); // add first dummy item - selection of this will be ignored        // TODO: add other items;    }    @Override    public int getCount() {        return items.size();    }    @Override    public Object getItem(int aPosition) {        return items.get(aPosition);    }    @Override    public long getItemId(int aPosition) {        return aPosition;    }    @Override    public View getView(int aPosition, View aView, ViewGroup aParent) {        TextView text = new TextView(context);        if (aPosition == 0) {            text.setText("-- Please select --"); // text for first dummy item        } else {            text.setText(items.get(aPosition).toString());            // or use whatever model attribute you'd like displayed instead of toString()        }        return text;    }}

I guess (haven't tried this) the same effect could be achieved using setSelected(false) instead of setSelection(0), but re-setting to "please select" suits my purposes fine. And, "look, Ma, no flag!" (Although I guess ignoring 0 selections is not that dissimilar.)

Hopefully, this can help someone else out there with a similar use case. :-) For other use cases, Felix' answer may be more suitable (thanks Felix!).


Look. I don't know if this will help you, but since you seem tired of looking for an answer without much success, this idea may help you, who knows...

The Spinner class is derived from AbsSpinner. Inside this, there is this method:

void setSelectionInt(int position, boolean animate) {        if (position != mOldSelectedPosition) {            mBlockLayoutRequests = true;            int delta  = position - mSelectedPosition;            setNextSelectedPositionInt(position);            layout(delta, animate);            mBlockLayoutRequests = false;        }    }

This is AFAIK taken from 1.5 source. Perhaps you could check that source, see how Spinner/AbsSpinner works, and maybe extend that class just enough to catch the proper method and not check if position != mOldSelectedPosition.

I mean... that's a huge "maybe" with a lot of "ifs" (android versioning comes to mind etc.), but since you seem frustrated (and I've been there with Android many times), maybe this can give you some "light". And I assume that there are no other obvious answers by looking at your previous research.

I wish you good luck!