Android Spinner - How to default list selection to none

70,420

Solution 1

My data-sizes.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="chunks">
        <item>2</item>
        <item>4</item>
        <item>8</item>
        <item>16</item>
        <item>32</item>
    </string-array>
</resources>

In main.xml:

<Spinner android:id="@+id/spinnerSize"  
android:layout_marginLeft="50px"
android:layout_width="fill_parent"                  
android:drawSelectorOnTop="true"
android:layout_marginTop="5dip"
android:prompt="@string/SelectSize"
android:layout_marginRight="30px"
android:layout_height="35px" /> 

In Java Code:

Spinner spinnerSize;
ArrayAdapter adapter;

...

spinnerSize = (Spinner)findViewById(R.id.spinnerSize);
adapter = ArrayAdapter.createFromResource(this, R.array.chunks, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerSize.setAdapter(adapter);
spinnerSize.setOnItemSelectedListener(new MyOnItemSelectedListener());

...

class MyOnItemSelectedListener implements OnItemSelectedListener {

    public void onItemSelected(AdapterView<?> parent,
        View view, int pos, long id) {
        chunkSize = new Integer(parent.getItemAtPosition(pos).toString()).intValue();
    }
    public void onNothingSelected(AdapterView<?> parent) {
      // Dummy
    }
}

So, although I can see 2 as my first default item, nothing happens unless user actually selects it.

Hope this helps!

Solution 2

If you want, there is a decorater spinnerAdapter witch add automatically a default value :



    protected class SpinnerAdapterWithNoValue implements SpinnerAdapter {

        private SpinnerAdapter _current;
        private final static String defaultValue = "Choisir";

        public SpinnerAdapterWithNoValue(SpinnerAdapter base) {
            _current = base;
        }

        @Override
        public int getCount() {
            return _current.getCount() + 1;
        }

        @Override
        public Object getItem(int position) {
            if (position == 0 || position == -1) {
                return null;
            }
            return _current.getItem(position - 1);
        }

        @Override
        public long getItemId(int position) {
            if (position == 0 || position == -1) {
                return -1;
            }
            return _current.getItemId(position - 1);
        }

        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == -1) {
                return -1;
            }
            return _current.getItemViewType(position - 1);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (position == 0 || position == -1) {
                final TextView v = (TextView) ((LayoutInflater) getContext().getSystemService(
                        Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.spinner_text, parent, false);
                v.setText(defaultValue);
                return v;
            }
            return _current.getView(position - 1, convertView, parent);
        }

        @Override
        public int getViewTypeCount() {
            return _current.getViewTypeCount();
        }

        @Override
        public boolean hasStableIds() {
            return _current.hasStableIds();
        }

        @Override
        public boolean isEmpty() {
            return _current.isEmpty();
        }

        @Override
        public void registerDataSetObserver(DataSetObserver observer) {
            _current.registerDataSetObserver(observer);
        }

        @Override
        public void unregisterDataSetObserver(DataSetObserver observer) {
            // TODO Auto-generated method stub
            _current.unregisterDataSetObserver(observer);
        }

        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            if (position == 0 || position == -1) {
                CheckedTextView v = (CheckedTextView) ((LayoutInflater) getContext().getSystemService(
                        Context.LAYOUT_INFLATER_SERVICE)).inflate(android.R.layout.simple_spinner_dropdown_item, parent,
                        false);
                v.setText(defaultValue);
                return v;
            }
            return _current.getDropDownView(position - 1, convertView, parent);
        }
    }


Then you can create your own spinner using this decorater :



    public class SpinnerWithNoValue extends Spinner {

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

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

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

        @Override
        public void setAdapter(SpinnerAdapter orig) {
            final SpinnerAdapter adapter = new SpinnerAdapterWithNoValue(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);
            }
        }

        /*
         * getSelectedItem renvoi null si la valeur par defaut est séléctionnée
         * 
         * @see android.widget.AdapterView#getSelectedItem()
         */
        @Override
        public Object getSelectedItem() {
            return super.getSelectedItem();
        }
    }


You just have to change the spinner declaration in your xml layout :



com.myproject.SpinnerWithNoValue


If you want, you can change the code to set the default text in the tag of your spinner.

Solution 3

The Spinner will always have a selection. What you can do is make the Spinner display something like "Select"or "Select a option"...

To do this you can make your list options to be

actionList = {"Select", "Desactivate" }

and

public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {               
        actionList[0] = "Activate";
        ...
 }

or you can do something more complicated like overrides the Spinner View or put a button instead with nothing on it and when it's clicked you create your spinner.

Share:
70,420
linsek
Author by

linsek

Updated on April 12, 2020

Comments

  • linsek
    linsek about 4 years

    I have an Android form that needs to update itself based on certain selections. The form is currently made up of 2 Spinners (A and B). Spinner B not created until Spinner A's selection is made. After the selection is made B will be displayed to the view and it's contents dynamically filled based on A's selection. Here is my code:

    public class MyForm extends Activity 
    {   
        private final int SEL_ACTIVATE = 0;
        private final int SEL_DEACTIVATE = 1;
    
        private static final String[] actionList = {"Activate", "Deactivate" };
    
        @Override
        public void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            table = (TableLayout) findViewById(R.id.table);
    
            showListA(table);
        }
    
        public void showListA(View v)
        {        
            rowAction = new TableRow(this);
    
            Spinner spinner = new Spinner(this);
            spinner.setPrompt("Select...");
            spinner.setOnItemSelectedListener(
                new OnItemSelectedListener() 
                {
                    public void onItemSelected(AdapterView<?> parent, View v, int position, long id) 
                    {
                        switch (position)
                        {
                        case SEL_ACTIVATE:
                        case SEL_DEACTIVATE:
                            showListB(v);
                            break;
                        }
                    }
    
                    public void onNothingSelected(AdapterView<?> arg0) 
                    {
                        // TODO Auto-generated method stub
                    }
            });
    
            ArrayAdapter<String> adapter = new ArrayAdapter<String> (this, android.R.layout.simple_spinner_item, actionList);
            adapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);
            spinner.setAdapter(adapter);
    
            rowAction.addView(tvAction);
            rowAction.addView(spinner);
    
            table.addView(rowAction, new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        }
    
        ...
    }
    

    This code works correctly. When either "Activate" or "Deactivate" are selected from the list, showListB() executes which is very similar to showListA() in how it creates a new row which contains Label and Spinner.

    The problem is that, by default, "Activate" is shown in the Spinner which executes showListB() and right off the bat, the second part of the form is created based on the "Activate" option. The only workaround that I can come up with is to add a third field to the Spinner like so:

    private static final String[] actionList = {"None", "Activate", "Deactivate" };
    
    ...
    
    switch (position)
    {
    case SEL_NONE:
        break;
    case SEL_ACTIVATE:
    case SEL_DEACTIVATE:
        showListB(v);
        break;
    }
    

    This works... but I don't want a third option in the list. I just want it to, by default, be blank or show some sort of 'prompt' text that is not an option in the list once it is pressed. Is this possible?

    Thanks

    EDIT:

    xml content:

    <Spinner
        android:id="@+id/spinnerAction"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>  
    
  • linsek
    linsek over 13 years
    I believe I am doing this in the Java source through spinner.setPrompt("Available Actions");. But I just attempted to add your source line in the XML and received the following error: error: Error: String types not allowed (at 'prompt' with value 'test'). Which is odd, because the API for <Spinner> says prompt should be a valid argument...
  • Phobos
    Phobos over 13 years
    I overlooked the reference in the documentation. Prompt has to be referenced.
  • linsek
    linsek over 13 years
    I'm sorry, I don't quite follow your edit. "Try referencing a string value"?
  • dylan murphy
    dylan murphy about 13 years
    this does not work. prompt just gives the spinner a title, it does not take place of any of the elements. @Phobos is right though, you cannot say android:prompt="some text" it has to be android:prompt="@string/text_string" or whatever
  • TheCottonSilk
    TheCottonSilk over 12 years
    Please give reasons when you think the answer is not useful(-1), that way all can understand why this answer is not good and show the better way to do it! Thanks.
  • Tony Chan
    Tony Chan over 10 years
    To clarify, this works because you're setting the OnItemSelectedListener after you set the Adapter correct?
  • CACuzcatlan
    CACuzcatlan over 7 years
    What is the chunkSize variable?