tags:

views:

14067

answers:

5

In Android, I want to use a Spinner that initially (when the user has not made a selection yet) displays the text "Select One". When the user clicks the spinner, the list of items is displayed and the user selects one of the options. After the user has made a selection, the selected item is displayed in the Spinner instead of "Select One".

I have the following code to create a Spinner:

String[] items = new String[] {"One", "Two", "Three"};
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

With this code, initially the item "One" is displayed. I could just add a new item "Select One" to the items, but then "Select One" would also be displayed in the dropdown list as first item, which is not what I want.

Any ideas? Thanks in advance.

+7  A: 
Casey
It's not just a matter of needing to show "Select One", it also addresses the case where the spinner value may optionally be left blank.
greg7gkb
A: 

I found this solution:

String[] items = new String[] {"Select One", "Two", "Three"};
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
 @Override
 public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {               
        items[0] = "One";
        selectedItem = items[position];

 }

 @Override
 public void onNothingSelected(AdapterView<?> arg0) {
 }
    });

Just change the array[0] with "Select One" and then in the onItemSelected rename it in "One".

Not a classy solution... but works :D

Marco

Marco da Gualdo
+1  A: 

Here's a general solution that overrides the Spinner view. It overrides setAdapter() to set the initial position to -1, and proxies the supplied SpinnerAdapter to display the prompt string for position<0.

This has been tested on android 1.5 through 2.2, but buyer beware! Because this solution relies on reflection to call the private AdapterView.setNextSelectedPositionInt() and AdapterView.setSelectedPositionInt(), it's not guaranteed to work in future OS updates. It seems likely that it will, but it is by no means guaranteed.

Normally I wouldn't condone something like this, but this question has been asked enough times and it seems like a reasonable enough request that I thought I would post my solution.

/**
 * A modified Spinner that doesn't automatically select the first entry in the list.
 *
 * Shows the prompt if nothing is selected.
 *
 * Limitations: does not display prompt if the entry list is empty.
 */
public class NoDefaultSpinner extends Spinner {

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

    public NoDefaultSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setAdapter(SpinnerAdapter orig ) {
        final SpinnerAdapter adapter = newProxy(orig);

        super.setAdapter(adapter);

        try {
            final Method m = AdapterView.class.getDeclaredMethod("setNextSelectedPositionInt",int.class);
            m.setAccessible(true);
            m.invoke(this,-1);

            final Method n = AdapterView.class.getDeclaredMethod("setSelectedPositionInt",int.class);
            n.setAccessible(true);
            n.invoke(this,-1);

        } catch( Exception e ) {
            throw new RuntimeException(e);
        }
    }

    protected SpinnerAdapter newProxy(SpinnerAdapter obj) {
        return (SpinnerAdapter) java.lang.reflect.Proxy.newProxyInstance(
                obj.getClass().getClassLoader(),
                new Class[]{SpinnerAdapter.class},
                new SpinnerAdapterProxy(obj));
    }    



    /**
     * Intercepts getView() to display the prompt if position < 0
     */
    protected class SpinnerAdapterProxy implements InvocationHandler {

        protected SpinnerAdapter obj;
        protected Method getView;


        protected SpinnerAdapterProxy(SpinnerAdapter obj) {
            this.obj = obj;
            try {
                this.getView = SpinnerAdapter.class.getMethod("getView",int.class,View.class,ViewGroup.class);
            } catch( Exception e ) {
                throw new RuntimeException(e);
            }
        }

        public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
            try {
                return m.equals(getView) && (Integer)(args[0])<0 ? getView((Integer)args[0],(View)args[1],(ViewGroup)args[2]) : m.invoke(obj, args);
            } catch (InvocationTargetException e) {
                throw e.getTargetException();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }


        protected View getView(int position, View convertView, ViewGroup parent) throws IllegalAccessException {
            if( position<0 ) {
                final TextView v = (TextView) ((LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(android.R.layout.simple_spinner_item,parent,false);
                v.setText(getPrompt());
                return v;
            }

            return obj.getView(position,convertView,parent);
        }

    }


}
Mike
A: 

Hi ,

I got the same problem for spinner, with empty selection.

I found a better solution, if you still having this problem have a look at this simple code.

Spinner lCreditOrDebit = (Spinner)lCardPayView.findViewById(R.id.CARD_TYPE);
spinneradapter lAdapter = new spinneradapter(BillPayScreen.this,ndroid.R.layout.simple_spinner_item,getResources().getStringArray(R.array.creditordebit));
lAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
lCreditOrDebit.setAdapter(lAdapter);

here spinneradapter is a small customization for arrayadapter, looks like this:

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

public class spinneradapter extends ArrayAdapter<String>{
      private Context m_cContext;
      public spinneradapter(Context context,int textViewResourceId, String[] objects) {

            super(context, textViewResourceId, objects);
            this.m_cContext = context;
      }

      boolean firsttime = true;
      @Override
      public View getView(int position, View convertView, ViewGroup parent) { 
            if(firsttime){
                  firsttime = false;
                  //just return some empty view
                  return new ImageView(m_cContext);
            }
            //let the array adapter takecare this time      
            return super.getView(position, convertView, parent);
      }

}

I hope that it will help you.

Regards RajaSekhar

Rajasekhar