How to make an Android Spinner with initial text "Select One"?
Asked Answered
B

37

608

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.

How can I fix this problem?

Blackcap answered 15/5, 2009 at 8:9 Comment(6)
Perfect solution lies in this question : #9863878 Just override getDropDownView() method.Zampardi
Have you tried setting the first element of your adapter to "Select One"?Ceremonial
[Here other great nice solution!][1] [1]: #9863878Yves
reusable spinner : github.com/henrychuangtw/ReuseSpinnerChickenlivered
android--code.blogspot.in/2015/08/android-spinner-hint.html another good tutorialBay
Theres a far better solution - Use AutocompleteTextView, and set clickable and focusable to false. Add the items as suggestions list. Wrap the AutocompleteTextView in a TextInputLayout and you can set a hint. So the hint is initially shown, and when you click on it, the list of suggestions (your items) is displayed. The clickable and focusable on false will prevent the keyboard from popping out and any manual input, basically making it a perfect dropdown menu.Kissiah
C
265

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 less than 0.

This has been tested on Android 1.5 through 4.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);
        }
    }
}
Cuccuckold answered 6/8, 2010 at 19:25 Comment(20)
your method very well ,but i found that i choice one item ,not only the text of the item,but also the choice icon are show at the spinnerDummy
@Cuccuckold Do you have any idea how to clear the selection after the user set it? I tried refactoring the two invoke() calls into a clearSelection() method, but it doesn't really work. Although the popup list shows the formerly-selected item as unselected, the spinner widget still shows it as selected, and if the user selects the same item again, onItemSelected() is not called.Zarla
could some explain how to use above class ?Whatley
This solution isn't 100% perfect on Android 4.2 (Cyanogenmod 10.1), using android:entries. The height of the inflated TextView is smaller thant the height of whichever resource the default Adapter inflates. So, when you actually select an option, the height increases, ~10px in my Galaxy S, which isn't acceptable. I've tried several things (gravity, padding, margin, etc.) and none worked reliably across devices, so I'm going to opt for a different solution.Studio
@Cuccuckold Can you add an example of how to use this? I have created a spinner in the Graphical Layout that I usually get a pointer to with Spinner spinner = (Spinner) findViewById(R.id.spinner1); - how do I make it use the NoDefaultSpinner behavior?Dillondillow
@DavidDoria You have to use the NoDefaultSpinner class in your layout file. Copy the source from above into your project, e.g. into package com.example.customviews. Now in your layout xml, instead of <Spinner ...> use <com.example.customviews.NoDefaultSpinner ...> The rest of the code can stay the same. Don't forget to add the android:prompt attribute to the <com.example.customviews.NoDefaultSpinner> view in your layout.Zacheryzack
To prevent the spinner from resizing itself don't use the entries property in the XML and do it via Java with something like this private ArrayAdapter<CharSequence> createSpinnerAdapterFromArray(int arrayResource){ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(), arrayResource, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); return adapter; }Kunlun
How do i put the items to appear in the drop down menu ? Does it works in 4.4?Peewee
@Cuccuckold spinnerBrand.setSelection(-1); is not workingIneludible
Works on 4.4. Had to make the height of my spinner to around 50dp to see the prompt text clearly, but hey it works. ThanksTroop
Just tried it. Android Studio says Cannot resolve symbol 'SpinnerAdapterProxy'. What do I do?Emergence
How can I reset the spinner to contain no default selection after a selection has been made? The code only shows how to set the default to no selection. Something like setSelection(-1) does not work.Circuity
Solved. In order to get no selection back after having selected an item you can do: public void setNoSelection() { 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); } setSelection(-1, false); }Circuity
Make NoDefaultSpinner extend AppCompatSpinner if you're using the appcompat library.Hindi
I really really wanted this solution to work but no matter what I tried, including implementing and invoking setNoSelection, getView was never called with -1. This is using AppCompatSpinner as the base class in SDK version 23. NoDefaultSpinner:invoke gets called for getView but args start at 0, not -1Draught
Great, this also works in 4.3. and for those who don't know use this class(I just figured out...)create this new class in your projectTyrrell
Great, this also works in 4.3. and for those who don't know how to use this class(I just figured out...): 1. create this new class in your project 2. update all those "spinner" originally definined in your java file and layout xml files to "NoDefaultSpinner "(e.g. "Spinner spinner1" > "NoDefaultSpinner spinner1" ) and "com.***.***.NoDefaultSpinner "("<spinner></spinner>" > "<com.***.***.NoDefaultSpinner></com.***.***.NoDefaultSpinner>") respectively. 3.rebuild your project. that's all, it should work now, no need to do any modifications more than this, in my case.Tyrrell
can any one look into my question ?Guimpe
Throws 'Fatal signal 11 (SIGSEGV)' on some Samsung Galaxy devices with Android 6.0. The cause is m.equals(getView).Glasper
I was able to clear the selection by deriving from AppCompatSpinner (or by delegating to it) and resetting the adapter by storing it in a temporary variable: ` fun clearSelection() { val tmp = adapter spinner.adapter = null spinner.adapter = tmp } `Midkiff
H
313

What you can do is decorate your SpinnerAdapter with one that presents a 'Select Option...' View initially for the Spinner to display with nothing selected.

Here is a working example tested for Android 2.3, and 4.0 (it uses nothing in the compatibility library, so it should be fine for awhile) Since it's a decorator, it should be easy to retrofit existing code and it works fine with CursorLoaders also. (Swap cursor on the wrapped cursorAdapter of course...)

There is an Android bug that makes this a little tougher to re-use views. (So you have to use the setTag or something else to ensure your convertView is correct.) Spinner does not support multiple view types

Code notes: 2 constructors

This allows you to use a standard prompt or define your own 'nothing selected' as the first row, or both, or none. (Note: Some themes show a DropDown for a Spinner instead of a dialog. The Dropdown doesn't normally show the prompt)

You define a layout to 'look' like a prompt, for example, grayed out...

Initial nothing selected

Using a standard prompt (notice that nothing is selected):

With a standard prompt

Or with a prompt and something dynamic (could have had no prompt also):

Prompt and nothing selected row

Usage in above example

Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.planets_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setPrompt("Select your favorite Planet!");

spinner.setAdapter(
      new NothingSelectedSpinnerAdapter(
            adapter,
            R.layout.contact_spinner_row_nothing_selected,
            // R.layout.contact_spinner_nothing_selected_dropdown, // Optional
            this));

contact_spinner_row_nothing_selected.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    style="?android:attr/spinnerItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textSize="18sp"
    android:textColor="#808080"
    android:text="[Select a Planet...]" />

NothingSelectedSpinnerAdapter.java

import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.SpinnerAdapter;

/**
 * Decorator Adapter to allow a Spinner to show a 'Nothing Selected...' initially
 * displayed instead of the first choice in the Adapter.
 */
public class NothingSelectedSpinnerAdapter implements SpinnerAdapter, ListAdapter {

    protected static final int EXTRA = 1;
    protected SpinnerAdapter adapter;
    protected Context context;
    protected int nothingSelectedLayout;
    protected int nothingSelectedDropdownLayout;
    protected LayoutInflater layoutInflater;

    /**
     * Use this constructor to have NO 'Select One...' item, instead use
     * the standard prompt or nothing at all.
     * @param spinnerAdapter wrapped Adapter.
     * @param nothingSelectedLayout layout for nothing selected, perhaps
     * you want text grayed out like a prompt...
     * @param context
     */
    public NothingSelectedSpinnerAdapter(
      SpinnerAdapter spinnerAdapter,
      int nothingSelectedLayout, Context context) {

        this(spinnerAdapter, nothingSelectedLayout, -1, context);
    }

    /**
     * Use this constructor to Define your 'Select One...' layout as the first
     * row in the returned choices.
     * If you do this, you probably don't want a prompt on your spinner or it'll
     * have two 'Select' rows.
     * @param spinnerAdapter wrapped Adapter. Should probably return false for isEnabled(0)
     * @param nothingSelectedLayout layout for nothing selected, perhaps you want
     * text grayed out like a prompt...
     * @param nothingSelectedDropdownLayout layout for your 'Select an Item...' in
     * the dropdown.
     * @param context
     */
    public NothingSelectedSpinnerAdapter(SpinnerAdapter spinnerAdapter,
            int nothingSelectedLayout, int nothingSelectedDropdownLayout, Context context) {
        this.adapter = spinnerAdapter;
        this.context = context;
        this.nothingSelectedLayout = nothingSelectedLayout;
        this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
        layoutInflater = LayoutInflater.from(context);
    }

    @Override
    public final View getView(int position, View convertView, ViewGroup parent) {
        // This provides the View for the Selected Item in the Spinner, not
        // the dropdown (unless dropdownView is not set).
        if (position == 0) {
            return getNothingSelectedView(parent);
        }
        return adapter.getView(position - EXTRA, null, parent); // Could re-use
                                                 // the convertView if possible.
    }

    /**
     * View to show in Spinner with Nothing Selected
     * Override this to do something dynamic... e.g. "37 Options Found"
     * @param parent
     * @return
     */
    protected View getNothingSelectedView(ViewGroup parent) {
        return layoutInflater.inflate(nothingSelectedLayout, parent, false);
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        // Android BUG! http://code.google.com/p/android/issues/detail?id=17128 -
        // Spinner does not support multiple view types
        if (position == 0) {
            return nothingSelectedDropdownLayout == -1 ?
              new View(context) :
              getNothingSelectedDropdownView(parent);
        }

        // Could re-use the convertView if possible, use setTag...
        return adapter.getDropDownView(position - EXTRA, null, parent);
    }

    /**
     * Override this to do something dynamic... For example, "Pick your favorite
     * of these 37".
     * @param parent
     * @return
     */
    protected View getNothingSelectedDropdownView(ViewGroup parent) {
        return layoutInflater.inflate(nothingSelectedDropdownLayout, parent, false);
    }

    @Override
    public int getCount() {
        int count = adapter.getCount();
        return count == 0 ? 0 : count + EXTRA;
    }

    @Override
    public Object getItem(int position) {
        return position == 0 ? null : adapter.getItem(position - EXTRA);
    }

    @Override
    public int getItemViewType(int position) {
        return 0;
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    @Override
    public long getItemId(int position) {
        return position >= EXTRA ? adapter.getItemId(position - EXTRA) : position - EXTRA;
    }

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

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

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

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        adapter.unregisterDataSetObserver(observer);
    }

    @Override
    public boolean areAllItemsEnabled() {
        return false;
    }

    @Override
    public boolean isEnabled(int position) {
        return position != 0; // Don't allow the 'nothing selected'
                                             // item to be picked.
    }

}
Heathheathberry answered 31/8, 2012 at 19:14 Comment(25)
This is an elegant solution to the problem. Code works exactly as copy'n'pasted into my project. +1 for no reflection required.Frug
Is there a demo project for this that shows the implementation of this class? I'm having trouble getting it to work. Do you use this class as the adapter, or pass an adapter to it and then use it?Roarke
@Chris, Added the code for the usage in the above example, hope that helps!Heathheathberry
This is a great solution. If anyone wants to know how to override the title not just before an item is selected, but at all times, in the getView() call, just return getNothingSelectedView (or any other custom view) at all times. The dropdown list will still be populated with items from your adapter, but you can now control the title AFTER something is selected as well.Exalted
@Heathheathberry Is there a way to get it to still display the [Select a planet] even if the spinner is empty? That is, if I use: ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item); then no text is displayed in spinner all. Then as soon as I adapter.add("Test1"); the "[Select a planet]" is displayed like I would like.Dillondillow
Just a note to augment this wonderful answer: if your planet names are longer than the space reserved to the spinner's width, you'll need to set the spinner's layout_width attribute to wrap_content and set a right padding (I used 50dp) in order to have the same visual effect as a real spinner for the TextView used as the selection; otherwise, the TextView is at risk of expanding on the right and putting the background arrow out of sight.Amen
This is a really elegant solution to a problem that should not exists (try Iphone development). Great and thanks! Glad that somebody remembered patterns etc.Conformist
This is good solution for not only the missing "Select One..." title from Android Spinner, but also that the first item is automatically selected when the spinner is created. With this, you can perform actions only when the user has selected some item. Also the user can actually select the first valid option after clicking the spinner.Undressed
This is the best solution by far. Can't believe this kind of solution has not made it to the SDK after all this time. Thanks!Washstand
@David Doria To show "[Select a planet]" even if the items array is empty I made NothingSelectedSpinnerAdapter.getCount() {return adapter.getCount() + EXTRA;}Koralle
any solution for api >= 21Stoppage
Should work correctly now with Lollipop. I had coded it to work when "Spinner does not support multiple view types" (code.google.com/p/android/issues/detail?id=17128) was fixed. But it never will be, bug is closed... bummer.Heathheathberry
broken in lollipop. java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tata.dsms/com.tata.dsms.activity.AddAccountActivity}: java.lang.IllegalArgumentException: Spinner adapter view type count must be 1 it is being enforced. code.google.com/p/android/issues/detail?id=79011Adala
@prashantwosti, the code was updated to work with Lollipop. Specifically getItemViewType() and getViewTypeCount().Heathheathberry
@Heathheathberry I'm using this and this worked, but I have some non mandatory Spinners, this crashed when I skip selecting a value. How can I overcome this?Intimacy
@JohnDavid, how did it crash exactly?Heathheathberry
@Heathheathberry once selected an item from the spinner can I undo and select "[Select a planet]"?Stowaway
Attention after go to a position and back with back key, spinner position will be remain to that position and you can not click it again. to change this behavior write this on OnItemSelectedListener: switch (position) { case 1: //some code break; case 2: //some code } spinner.setSelection(0);Ontina
who can i reuse the convertView using setTag?Swithin
@Stowaway check this adapter. It should work for your question since I had the same problem https://mcmap.net/q/65529/-selected-item-at-position-0-in-android-spinnerStreit
I am very new in android :) My app has more than one spinner. I create one contact_spinner_row_nothing_selected.xml file in my project. How is it possible to pass a string and change the "[Select a Planet...]" (android.text) for each spinner, For example one most be "Select City" and other "Select Country"Boiled
@AlirezaFattahi, you'll need to have 2 nothing_selected_row xml files. Copy the example and make one like city_spinner_nothing_selected_row.xml and country_spinner_nothing_selected_row.xml. Set the correct text in each file and use in your spinners.Heathheathberry
Its an elegant solution, but it really ought to be built into Spinner itself. This not being there is a lacking feature.Londonderry
Invoking setSelection on the spinner component results in an off-by-one.Midkiff
this one is pretty cool, will try to implement this on my design! thanks a lot! it's 2021 and this code is still helping usProvencal
C
265

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 less than 0.

This has been tested on Android 1.5 through 4.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);
        }
    }
}
Cuccuckold answered 6/8, 2010 at 19:25 Comment(20)
your method very well ,but i found that i choice one item ,not only the text of the item,but also the choice icon are show at the spinnerDummy
@Cuccuckold Do you have any idea how to clear the selection after the user set it? I tried refactoring the two invoke() calls into a clearSelection() method, but it doesn't really work. Although the popup list shows the formerly-selected item as unselected, the spinner widget still shows it as selected, and if the user selects the same item again, onItemSelected() is not called.Zarla
could some explain how to use above class ?Whatley
This solution isn't 100% perfect on Android 4.2 (Cyanogenmod 10.1), using android:entries. The height of the inflated TextView is smaller thant the height of whichever resource the default Adapter inflates. So, when you actually select an option, the height increases, ~10px in my Galaxy S, which isn't acceptable. I've tried several things (gravity, padding, margin, etc.) and none worked reliably across devices, so I'm going to opt for a different solution.Studio
@Cuccuckold Can you add an example of how to use this? I have created a spinner in the Graphical Layout that I usually get a pointer to with Spinner spinner = (Spinner) findViewById(R.id.spinner1); - how do I make it use the NoDefaultSpinner behavior?Dillondillow
@DavidDoria You have to use the NoDefaultSpinner class in your layout file. Copy the source from above into your project, e.g. into package com.example.customviews. Now in your layout xml, instead of <Spinner ...> use <com.example.customviews.NoDefaultSpinner ...> The rest of the code can stay the same. Don't forget to add the android:prompt attribute to the <com.example.customviews.NoDefaultSpinner> view in your layout.Zacheryzack
To prevent the spinner from resizing itself don't use the entries property in the XML and do it via Java with something like this private ArrayAdapter<CharSequence> createSpinnerAdapterFromArray(int arrayResource){ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(), arrayResource, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); return adapter; }Kunlun
How do i put the items to appear in the drop down menu ? Does it works in 4.4?Peewee
@Cuccuckold spinnerBrand.setSelection(-1); is not workingIneludible
Works on 4.4. Had to make the height of my spinner to around 50dp to see the prompt text clearly, but hey it works. ThanksTroop
Just tried it. Android Studio says Cannot resolve symbol 'SpinnerAdapterProxy'. What do I do?Emergence
How can I reset the spinner to contain no default selection after a selection has been made? The code only shows how to set the default to no selection. Something like setSelection(-1) does not work.Circuity
Solved. In order to get no selection back after having selected an item you can do: public void setNoSelection() { 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); } setSelection(-1, false); }Circuity
Make NoDefaultSpinner extend AppCompatSpinner if you're using the appcompat library.Hindi
I really really wanted this solution to work but no matter what I tried, including implementing and invoking setNoSelection, getView was never called with -1. This is using AppCompatSpinner as the base class in SDK version 23. NoDefaultSpinner:invoke gets called for getView but args start at 0, not -1Draught
Great, this also works in 4.3. and for those who don't know use this class(I just figured out...)create this new class in your projectTyrrell
Great, this also works in 4.3. and for those who don't know how to use this class(I just figured out...): 1. create this new class in your project 2. update all those "spinner" originally definined in your java file and layout xml files to "NoDefaultSpinner "(e.g. "Spinner spinner1" > "NoDefaultSpinner spinner1" ) and "com.***.***.NoDefaultSpinner "("<spinner></spinner>" > "<com.***.***.NoDefaultSpinner></com.***.***.NoDefaultSpinner>") respectively. 3.rebuild your project. that's all, it should work now, no need to do any modifications more than this, in my case.Tyrrell
can any one look into my question ?Guimpe
Throws 'Fatal signal 11 (SIGSEGV)' on some Samsung Galaxy devices with Android 6.0. The cause is m.equals(getView).Glasper
I was able to clear the selection by deriving from AppCompatSpinner (or by delegating to it) and resetting the adapter by storing it in a temporary variable: ` fun clearSelection() { val tmp = adapter spinner.adapter = null spinner.adapter = tmp } `Midkiff
B
134

I ended up using a Button instead. While a Button is not a Spinner, the behavior is easy to customize.

First create the Adapter as usual:

String[] items = new String[] {"One", "Two", "Three"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_spinner_dropdown_item, items);

Note that I am using the simple_spinner_dropdown_item as the layout id. This will help create a better look when creating the alert dialog.

In the onClick handler for my Button I have:

public void onClick(View w) {
  new AlertDialog.Builder(this)
  .setTitle("the prompt")
  .setAdapter(adapter, new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {

      // TODO: user specific action

      dialog.dismiss();
    }
  }).create().show();
}

And that's it!

Baksheesh answered 26/4, 2011 at 12:55 Comment(7)
I agree with that answer. Besides, a button much more easy to style than a Spinner.Fairminded
@Baksheesh I have implemented the way u suggested, but the item which is selected before is not getting highlighted(means radio button must be higlighted with greeen dot in the middle).... How can i acheive this in OnClick() method of button. Please help me HRJ.....Chalkstone
The button with this layout thats perfect <Button android:id="@+id/city" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:gravity="left" android:background="@android:drawable/btn_dropdown" android:text="@string/city_prompt" />Alexandros
How would you then update the text of the button to reflect the selection, as would happen in a spinner?Dahlgren
@Dahlgren You could set the button text in your dialog onClick with myButton.setText("prompt");Karakul
problem: list rows have "value + radio button" but you cannot point which row is 'selected'Air
problem solution: just instead of SetAdapter use SetSingleChoiceItemsAir
E
68

First, you might be interested in the prompt attribute of the Spinner class. See the picture below, "Choose a Planet" is the prompt that can be set in the XML with android:prompt="".

enter image description here

I was going to suggest subclassing Spinner, where you could maintain two adapters internally. One adapter that has the "Select One" option, and the other real adapter (with the actual options), then using the OnClickListener to switch the adapters before the choices dialog is shown. However, after trying implement that idea I've come to the conclusion you cannot receive OnClick events for the widget itself.

You could wrap the spinner in a different view, intercept the clicks on the view, and then tell your CustomSpinner to switch the adapter, but seems like an awful hack.

Do you really need to show "Select One"?

Eckblad answered 15/5, 2009 at 22:42 Comment(3)
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.Bueschel
also, with this option, Earth is shown as the selection on the Spinner before anything has been chosen, for my app i would rather the user be able to tell they had not chosen anything yetVar
this doesnt really answer the question. people are looking for a way to have the spinner itself by default show "Select One" rather than the first item in the list of planets, in this exampleNeoplasty
P
62

This code has been tested and works on Android 4.4

enter image description here

Spinner spinner = (Spinner) activity.findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity, android.R.layout.simple_spinner_dropdown_item) {

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

                View v = super.getView(position, convertView, parent);
                if (position == getCount()) {
                    ((TextView)v.findViewById(android.R.id.text1)).setText("");
                    ((TextView)v.findViewById(android.R.id.text1)).setHint(getItem(getCount())); //"Hint to be displayed"
                }

                return v;
            }       

            @Override
            public int getCount() {
                return super.getCount()-1; // you dont display last item. It is used as hint.
            }

        };

        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        adapter.add("Daily");
        adapter.add("Two Days");
        adapter.add("Weekly");
        adapter.add("Monthly");
        adapter.add("Three Months");
        adapter.add("HINT_TEXT_HERE"); //This is the text that will be displayed as hint.


        spinner.setAdapter(adapter);
        spinner.setSelection(adapter.getCount()); //set the hint the default selection so it appears on launch.
        spinner.setOnItemSelectedListener(this);
Peewee answered 20/10, 2014 at 22:4 Comment(8)
getItem(getCount()) is underlined red for me? Cannot resolve method setHintOnshore
I have a doubt, saw many solutions in this thread..but why everybody is adding hint to the last. Is it wrong to add hint in the first row ?Riel
I can't set 'setOnItemSelectedListener(this);' cause i'm using 'implements NavigationView.OnNavigationItemSelectedListener', can I remove 'setOnItemSelectedListener(this);' without any issues?Glidebomb
@akashpatra The reason they add hint to last is that ArrayAdapter for spinner might get its values from different sources at run time.Hypogene
this really helped meEyeshade
this is the best answerFenella
Perfect answer!! :)Carpi
If nothing was selected and containing fragment view is detroyed then after the fragment restoration there will be the last item selected in the spinner instead of the hint.Amando
B
32

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 to "One".

Not a classy solution, but it works :D

Bibby answered 20/7, 2010 at 15:54 Comment(2)
This did not work for me. After choosing item "One" it still says "Select One".Lin
This wont work cause onItemSelected interface will call for first time always.Underwriter
N
24

Lots of answers here but I'm surprised no one suggested a simple solution: Place a TextView on top of the Spinner. Set a click listener on the TextView which hides the TextView shows the Spinner, and calls spinner.performClick().

Nievesniflheim answered 29/9, 2016 at 23:18 Comment(2)
This is my favorite answer. Thanks.Etalon
This approach has a small problem! For this, you need to set the width of the textview to the width of the spinner. So arrow icon of spinner will disappear! One remedy is that increase the number of layers e.g. adding a layer for arrow and a linear layout for both textview and arrow layer.Shammy
J
22

There is no default API to set hint on Spinner. To add it we need a small workaround with out that not safety reflection implementation

List<Object> objects = new ArrayList<Object>();
objects.add(firstItem);
objects.add(secondItem);
// add hint as last item
objects.add(hint);

HintAdapter adapter = new HintAdapter(context, objects, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

Spinner spinnerFilmType = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);

// show hint
spinner.setSelection(adapter.getCount());

Adapter source:

public class HintAdapter
        extends ArrayAdapter<Objects> {

    public HintAdapter(Context theContext, List<Object> objects) {
        super(theContext, android.R.id.text1, android.R.id.text1, objects);
    }

    public HintAdapter(Context theContext, List<Object> objects, int theLayoutResId) {
        super(theContext, theLayoutResId, android.R.id.text1, objects);
    }

    @Override
    public int getCount() {
        // don't display last item. It is used as hint.
        int count = super.getCount();
        return count > 0 ? count - 1 : count;
    }
}

Original source

Jez answered 31/3, 2014 at 23:44 Comment(7)
what is R.id.text1 ? is it any layout or view ? please elaborate your answerEngler
It should be android.R.id.text1Jez
I have a doubt, saw many solutions in this thread..but why everybody is adding hint to the last. Is it wrong to add hint in the first row ?Riel
@akashpatra I don't remember exactly, but seem there was some issue when I tried to make it as first item list. Anyway you can always try it and comment here, all magic here is around getCount methodJez
@YakivMospan I get a NPE when I use this, probably due to Reflection when using ProGuard. Do you know how to fix this?Cervelat
@Cervelat there is no Reflection in my code here. Please share your crash log and code that you've used, you can create another question for that.Jez
Super hack.. All other answers are look like some problems.. But your code looks surely no problem.. So I go with your answer.. it works superb..Noriega
J
9

I got the same problem for spinner, with an empty selection, and I found a better solution. 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. It 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 take care of it this time.
        return super.getView(position, convertView, parent);
    }
}
Juli answered 2/10, 2010 at 8:3 Comment(1)
The problem with this approach is that it still selects the first item in the list when the list pops up. Because that's already selected you can't touch it to select -- it acts as if no selected has happened.Decanal
C
7

You can change it to a Text View and use this:

android:style="@android:style/Widget.DeviceDefault.Light.Spinner"

and then define the android:text property.

Crifasi answered 9/8, 2013 at 2:25 Comment(2)
Works only for API 14 and above.Amen
android:style="..." or just style="..."? I tried both but nothing happened!Shammy
K
6

XML file:

<Spinner android:id="@+id/locationSpinner"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:prompt="@string/select_location" />

Activity:

private Spinner featuresSelection;
private ArrayAdapter<CharSequence> featuresAdapter;
private List<CharSequence> featuresList;

onCreate:

featuresList = new ArrayList<CharSequence>();
featuresAdapter = new ArrayAdapter<CharSequence>(this,
  android.R.layout.simple_spinner_item, featuresList);
featuresAdapter.setDropDownViewResource(
  android.R.layout.simple_spinner_dropdown_item);
featuresSelection = ((Spinner) yourActivity.this
  .findViewById(R.id.locationSpinner));
featuresSelection.setAdapter(featuresAdapter);
featuresSelection.setOnItemSelectedListener(
  new MyOnItemSelectedListener());

Some function (add things to the adapter programmatically)>

featuresAdapter.add("some string");

Now you have an empty spinner and you can write code to not open the dialog if empty. Or they can press back. But you also populate it with a function or another list during run time.

Kebab answered 4/11, 2010 at 21:39 Comment(1)
Also no need to notifyDataSetChanged() as it should be set to true by default.Kebab
L
5

In addition, There is a simple trick to show default:

You can add a default value in your list and then add all of your collection using list.addAll(yourCollection);

Sample workable code here:

List<FuelName> fuelList = new ArrayList<FuelName>();
                    fuelList.add(new FuelName(0,"Select One"));
                    fuelList.addAll(response.body());
                    ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, fuelList);
                    //fuelName.setPrompt("Select Fuel");
                    fuelName.setAdapter(adapter);
Leban answered 30/1, 2019 at 10:36 Comment(0)
A
4

I have a spinner on my main.xml and its id is @+id/spinner1

this is what i write in my OnCreate function :

spinner1 = (Spinner)this.findViewById(R.id.spinner1);
final String[] groupes = new String[] {"A", "B", "C", "D", "E", "F", "G", "H"};
ArrayAdapter<CharSequence> featuresAdapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, new ArrayList<CharSequence>());
featuresAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(featuresAdapter);
for (String s : groupes) featuresAdapter.add(s);

spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
     public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
         // Here go your instructions when the user chose something
         Toast.makeText(getBaseContext(), groupes[position], 0).show();
     }
     public void onNothingSelected(AdapterView<?> arg0) { }
});

It doesn't need any implementation in the class.

Aculeate answered 9/10, 2011 at 2:25 Comment(0)
F
4

I have tried like the following. Take a button and give the click event to it. By changing the button background, it seems to be a spinner.

Declare as global variables alertdialog and default value..

AlertDialog d;
static int default_value = 0;
final Button btn = (Button) findViewById(R.id.button1);
btn .setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v)
{
    //c.show();
    final CharSequence str[] = {"Android","Black Berry","Iphone"};
        AlertDialog.Builder builder =
          new AlertDialog.Builder(TestGalleryActivity.this).setSingleChoiceItems(
            str, default_value,new  DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int position)
            {
                Toast.makeText(TestGalleryActivity.this,
                               "" + position,
                               Toast.LENGTH_SHORT).show();
                default_value = position;
                btn.setText(str[position]);
                if(d.isShowing())
                    d.dismiss();
            }
        }).setTitle("Select Any");
        d = builder.create();
        d.show();
    }
});
Frederick answered 5/11, 2011 at 12:18 Comment(0)
M
3

Take a look at the iosched app for a general purpose solution to adding an element to the top of a list. In particular, if you are using a CursorAdapter, look at TracksAdapter.java which extends that definition to provide a "setHasAllItem" method and associated code to manage the list count to deal with the extra item at the top.

Using the custom adapter you can set the text to "Select One" or whatever else you may want that top item to say.

Martinsen answered 15/9, 2011 at 20:46 Comment(0)
S
3

I found many good solutions for this. most is working by adding an item to the end of adapter, and don't display the last item in drop-down list. The big problem for me was the spinner drop-down list will start from the bottom of the list. So user see the last items instead of the first items (in case of have many items to show), after touch the spinner for the first time.

So I put the hint item to the beginning of the list. and hide the first item in drop-down list.

private void loadSpinner(){

    HintArrayAdapter hintAdapter = new HintArrayAdapter<String>(context, 0);

    hintAdapter.add("Hint to be displayed");
    hintAdapter.add("Item 1");
    hintAdapter.add("Item 2");
            .
            .
    hintAdapter.add("Item 30");

    spinner1.setAdapter(hintAdapter);

    //spinner1.setSelection(0); //display hint. Actually you can ignore it, because the default is already 0
    //spinner1.setSelection(0, false); //use this if don't want to onItemClick called for the hint

    spinner1.setOnItemSelectedListener(yourListener);
}

private class HintArrayAdapter<T> extends ArrayAdapter<T> {

    Context mContext;

    public HintArrayAdapter(Context context, int resource) {
        super(context, resource);
        this.mContext = context
    }

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

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(android.R.layout.simple_spinner_item, parent, false);
        TextView texview = (TextView) view.findViewById(android.R.id.text1);

        if(position == 0) {
            texview.setText("");
            texview.setHint(getItem(position).toString()); //"Hint to be displayed"
        } else {
            texview.setText(getItem(position).toString());
        }

        return view;
    }

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

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view;

        if(position == 0){
            view = inflater.inflate(R.layout.spinner_hint_list_item_layout, parent, false); // Hide first row
        } else {
            view = inflater.inflate(android.R.layout.simple_spinner_dropdown_item, parent, false);
            TextView texview = (TextView) view.findViewById(android.R.id.text1);
            texview.setText(getItem(position).toString());
        } 

        return view;
    }
}

set the below layout in @Override getDropDownView() when position is 0, to hide the first hint row.

R.layout.spinner_hint_list_item_layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

</LinearLayout>
Stammer answered 24/10, 2014 at 0:52 Comment(0)
S
2

I think the easiest way is creating a dummy item on index 0 saying "select one" and then on saving maybe check that selection is not 0.

Squinty answered 14/11, 2011 at 16:28 Comment(2)
What about viewing the list of items? You want to see the "select one" position at the top? It's not only the matter of saving.Overmeasure
@KrzysztofWolny Spinner by default displays the item at position 0Applied
F
2

So this is my final example "all-in" for a button-spinner

In activity_my_form.xml

    <Button
        android:id="@+id/btnSpinnerPlanets"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="left|center_vertical"
        android:singleLine="true"
        android:text="@string/selectAPlanet"
        android:textSize="10sp"
        android:background="@android:drawable/btn_dropdown">
    </Button>

In strings.xml

<string name="selectAPlanet">Select planet&#8230;</string>

<string-array name="planets__entries">
    <item>The Sun with a name very long so long long long long longThe Sun with a name very long so long long long long longThe Sun with a name very long so long long long long long</item>
    <item>Mercury</item>
    <item>Venus</item>
    <item>Earth</item>
    <item>Mars</item>
    <item>Jupiter</item>
    <item>Saturn</item>
    <item>Uranus</item>
    <item>Neptune</item>
</string-array>

In MyFormActivity.java

public class MyFormActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ((Button) findViewById(R.id.btnSpinnerPlanets)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final String[] items = view.getResources().getStringArray(R.array.planets__entries);
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(MyFormActivity.this, android.R.layout.simple_spinner_dropdown_item, items);
                new AlertDialog.Builder(MyFormActivity.this).setTitle("the prompt").setAdapter(adapter, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ((Button) findViewById(R.id.btnSpinnerPlanets)).setText(items[which]);
                        dialog.dismiss();
                    }
                }).create().show();
            }
        });     

    }

}   

Finally I obtained a font size configurable no first item selectable button spinner!!! Thanks to HRJ

Flybynight answered 4/4, 2013 at 9:38 Comment(0)
K
2

The best solution I found for this is actually not to use a Spinner but an AutoCompleteTextView. Its basically an EditText with attached Spinner to show suggestions as you type - but, with the right config, it can behave exactly as the OP wishes and more.

XML:

<com.google.android.material.textfield.TextInputLayout
                android:id="@+id/item"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

            <androidx.appcompat.widget.AppCompatAutoCompleteTextView
                    android:id="@+id/input"
                    android:hint="Select one"
                    style="@style/AutoCompleteTextViewDropDown"/>
        </com.google.android.material.textfield.TextInputLayout>

Style:

<style name="AutoCompleteTextViewDropDown">
    <item name="android:clickable">false</item>
    <item name="android:cursorVisible">false</item>
    <item name="android:focusable">false</item>
    <item name="android:focusableInTouchMode">false</item>
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
</style>

As for the adapter use the basic ArrayAdapter or extend it to make your own, but no additional customization on the adapter side is necessary. Set the adapter on the AutoCompleteTextView.

Kissiah answered 14/8, 2019 at 9:30 Comment(0)
D
1

When extending SpinnerAdapter, you override two View-producing methods, getView(int, View, ViewGroup) and getDropDownView(int, View, ViewGroup). The first one supplies the View inserted into the Spinner itself; the second supplies the View in the drop-down list (as the name suggests). You can override the getView(...) so that, until an item has been selected, it displays a TextView containing a prompt; then, when you detect an item has been selected, you change it to display a TextView corresponding to that.

public class PromptingAdapter extends SpinnerAdapter {

    //... various code ...

    private boolean selectionmade = false;

    //call this method from the OnItemSelectedListener for your Spinner
    public setSelectionState(boolean b) {
        selectionmade = b;
    }

    @Override
    public View getView(int position, View recycle, ViewGroup container) {
        if(selectionmade) {
            //your existing code to supply a View for the Spinner
            //you could even put "return getDropDownView(position, recycle, container);"
        }
        else {
            View output;
            if(recycle instanceof TextView) {
                 output = recycle;
            }
            else {
                 output = new TextView();
                 //and layout stuff
            }
            output.setText(R.string.please_select_one);
            //put a string "please_select_one" in res/values/strings.xml
            return output;
        }
    }

//...
}
Damon answered 23/3, 2012 at 13:59 Comment(2)
I've discovered a flaw in this method: the Spinner automatically selects an item immediately. I'll find a way round this shortly.Damon
I spoke too soon. I have not given up, however. Note that according to the Spinner tutorial (which supposedly displays a Toast AFTER you have selected an item) this OUGHT to work: developer.android.com/resources/tutorials/views/…Damon
C
1

For those using Xamarin, here is the C# equivalent to aaronvargas's answer above.

using Android.Content;
using Android.Database;
using Android.Views;
using Android.Widget;
using Java.Lang;

namespace MyNamespace.Droid
{ 
  public class NothingSelectedSpinnerAdapter : BaseAdapter, ISpinnerAdapter, IListAdapter
  {
    protected static readonly int EXTRA = 1;
    protected ISpinnerAdapter adapter;
    protected Context context;
    protected int nothingSelectedLayout;
    protected int nothingSelectedDropdownLayout;
    protected LayoutInflater layoutInflater;

    public NothingSelectedSpinnerAdapter(ISpinnerAdapter spinnerAdapter, int nothingSelectedLayout, Context context) : this(spinnerAdapter, nothingSelectedLayout, -1, context)
    {
    }

    public NothingSelectedSpinnerAdapter(ISpinnerAdapter spinnerAdapter, int nothingSelectedLayout, int nothingSelectedDropdownLayout, Context context)
    {
      this.adapter = spinnerAdapter;
      this.context = context;
      this.nothingSelectedLayout = nothingSelectedLayout;
      this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
      layoutInflater = LayoutInflater.From(context);
    }

    protected View GetNothingSelectedView(ViewGroup parent)
    {
      return layoutInflater.Inflate(nothingSelectedLayout, parent, false);
    }

    protected View GetNothingSelectedDropdownView(ViewGroup parent)
    {
      return layoutInflater.Inflate(nothingSelectedDropdownLayout, parent, false);
    }

    public override Object GetItem(int position)
    {
      return position == 0 ? null : adapter.GetItem(position - EXTRA);
    }

    public override long GetItemId(int position)
    {
      return position >= EXTRA ? adapter.GetItemId(position - EXTRA) : position - EXTRA;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
      // This provides the View for the Selected Item in the Spinner, not
      // the dropdown (unless dropdownView is not set).
      if (position == 0)
      {
        return GetNothingSelectedView(parent);
      }

      // Could re-use the convertView if possible.
      return this.adapter.GetView(position - EXTRA, null, parent);
    }

    public override int Count
    {
      get
      {
        int count = this.adapter.Count;
        return count == 0 ? 0 : count + EXTRA;
      }
    }

    public override View GetDropDownView(int position, View convertView, ViewGroup parent)
    {
      // Android BUG! http://code.google.com/p/android/issues/detail?id=17128 -
      // Spinner does not support multiple view types
      if (position == 0)
      {
        return nothingSelectedDropdownLayout == -1 ?
          new View(context) :
          GetNothingSelectedDropdownView(parent);
      }

      // Could re-use the convertView if possible, use setTag...
      return adapter.GetDropDownView(position - EXTRA, null, parent);
    }

    public override int GetItemViewType(int position)
    {
      return 0;
    }

    public override int ViewTypeCount => 1;

    public override bool HasStableIds => this.adapter.HasStableIds;

    public override bool IsEmpty => this.adapter.IsEmpty;

    public override void RegisterDataSetObserver(DataSetObserver observer)
    {
      adapter.RegisterDataSetObserver(observer);
    }

    public override void UnregisterDataSetObserver(DataSetObserver observer)
    {
      adapter.UnregisterDataSetObserver(observer);
    }

    public override bool AreAllItemsEnabled()
    {
      return false;
    }

    public override bool IsEnabled(int position)
    {
      return position > 0;
    }
  }
}
Corral answered 11/8, 2016 at 17:26 Comment(0)
H
1

I also solved this problem by using the following code. Suppose you are having a list of items e.g.

ArrayList<Item> itemsArrayList = new ArrayList<Item>();
Item item1 = new Item();
item1.setId(1);
item1.setData("First Element");
Item item2 = new Item();
item2.setId(2);
Item2.setData("Second Element");
itemsArrayList.add(item1);
itemsArrayList.add(item2);

Now we have to provide the strings to spinner because spinner can not understand the object. So we will create an new array list with string items like this ->

ArrayList<String> itemStringArrayList = new ArrayList<String>();
for(Item item : itemsArrayList) {
    itemStringArrayList.add(item.getData());
}

Now we have itemStringArrayList array list with two string items. And we have to show the "Select Item" text as first item. So we have to insert an new string into the itemStringArrayList.

itemStringArrayList.add("Select Item");

Now we have an array list itemsArrayList and we want to show two elements in the drop down. But the condition here is ...If we don't select anything then Select Item should appear as first element which will not be enabled.

So we can implement this functionality like this. If you need to load the array list items into the android spinner. So you will have to use some adapter. So here i'll use the ArrayAdapter. We can use the customise adapter too.

ArrayAdapter<String> itemsArrayAdapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.spinner_item, itemsArrayList){
        @Override
        public boolean isEnabled(int position) {
            if(position == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        @Override
        public View getDropDownView(int position, View convertView,
                                    ViewGroup parent) {
            View view = super.getDropDownView(position, convertView, parent);
            TextView tv = (TextView) view;
            if(position == 0){
                // Set the hint text color gray
                tv.setTextColor(Color.GRAY);
            }
            else {
                tv.setTextColor(Color.BLACK);
            }
            return view;
        }
    };

itemsArrayAdapter.setDropDownViewResource(R.layout.spinner_item);
your_spinner_name.setAdapter(itemsArrayAdapter);

Here in this code. we are using the customised spinner layout i.e. R.layout.spinner_item. It's a simple text view

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:textStyle="italic"
    android:fontFamily="sans-serif-medium"
    />

We need to disable the first text in the spinner. So for the position 0 we are disabling the text. And color also we can set by overiding getDropDownView method. So in this way we will get the expected spinner.

Highlands answered 7/10, 2017 at 21:50 Comment(0)
L
1

I was facing the same problem yesterday and did not want to add a hidden item to the ArrayAdapter or use reflections, which works fine but is kind of dirty.

After reading many posts and trying around I found a solution by extending ArrayAdapter and Overriding the getView method.

import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

/**
 * A SpinnerAdapter which does not show the value of the initial selection initially,
 * but an initialText.
 * To use the spinner with initial selection instead call notifyDataSetChanged().
 */
public class SpinnerAdapterWithInitialText<T> extends ArrayAdapter<T> {

    private Context context;
    private int resource;

    private boolean initialTextWasShown = false;
    private String initialText = "Please select";

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a TextView to use when
     *                 instantiating views.
     * @param objects The objects to represent in the ListView.
     */
    public SpinnerAdapterWithInitialText(@NonNull Context context, int resource, @NonNull T[] objects) {
        super(context, resource, objects);
        this.context = context;
        this.resource = resource;
    }

    /**
     * Returns whether the user has selected a spinner item, or if still the initial text is shown.
     * @param spinner The spinner the SpinnerAdapterWithInitialText is assigned to.
     * @return true if the user has selected a spinner item, false if not.
     */
    public boolean selectionMade(Spinner spinner) {
        return !((TextView)spinner.getSelectedView()).getText().toString().equals(initialText);
    }

    /**
     * Returns a TextView with the initialText the first time getView is called.
     * So the Spinner has an initialText which does not represent the selected item.
     * To use the spinner with initial selection instead call notifyDataSetChanged(),
     * after assigning the SpinnerAdapterWithInitialText.
     */
    @Override
    public View getView(int position, View recycle, ViewGroup container) {
        if(initialTextWasShown) {
            return super.getView(position, recycle, container);
        } else {
            initialTextWasShown = true;
            LayoutInflater inflater = LayoutInflater.from(context);
            final View view = inflater.inflate(resource, container, false);

            ((TextView) view).setText(initialText);

            return view;
        }
    }
}

What Android does when initialising the Spinner, is calling getView for the selected item before calling getView for all items in T[] objects. The SpinnerAdapterWithInitialText returns a TextView with the initialText, the first time it is called. All the other times it calls super.getView which is the getView method of ArrayAdapter which is called if you are using the Spinner normally.

To find out whether the user has selected a spinner item, or if the spinner still displays the initialText, call selectionMade and hand over the spinner the adapter is assigned to.

Lifton answered 9/2, 2018 at 9:57 Comment(0)
W
1

See the answer with lightweight and high customisable library:

https://mcmap.net/q/65531/-hint-on-spinner-on-android-spinner-with-kotlin

<com.innowisegroup.hintedspinner.HintedSpinner
android:id="@+id/hintedSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
app:hintTextSize="24sp"
app:hintTextColor="@color/red"
app:hint="Custom hint"
app:withDivider="true"
app:dividerColor="@color/dark_green"
app:arrowDrawable="@drawable/example_arrow_4"
app:arrowTint="@color/colorAccent"
app:popupBackground="@color/light_blue"
app:items="@array/text" />

Collapsed spinner: enter image description here

Expanded spinner:

enter image description here

Waylonwayman answered 22/7, 2022 at 21:14 Comment(0)
G
0

I'd just use a RadioGroup with RadioButtons if you only have three choices, you can make them all unchecked at first.

Geez answered 19/8, 2011 at 16:53 Comment(0)
M
0

None of the previously submitted answers really worked the way I wanted to solve this issue. To me the ideal solution would provide the “Select One” (or whatever initial text) when the spinner is first displayed. When the user taps the spinner, the initial text shouldn’t be a part of the drop down that is displayed.

To further complicate my particular situation, my spinner data is coming form a cursor that is loaded via the LoaderManager callbacks.

After considerable experimentation I came up with the following solution:

public class MyFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>{

private static final String SPINNER_INIT_VALUE = "Select A Widget";
private Spinner mSpinner;
private int mSpinnerPosition;
private boolean mSpinnerDropDownShowing = false;
private View mSpinnerDropDown;

private MyCursorAdapter mCursorAdapter;

...

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
...

mCursorAdapter = new MyCursorAdapter(getActivity());

mSpinner = (Spinner) rootView.findViewById(R.id.theSpinner);
mSpinner.setOnTouchListener(mSpinnerTouchListener);
mSpinner.setAdapter(mCursorAdapter);

...
}

//Capture the touch events to toggle the spinner's dropdown visibility
private OnTouchListener mSpinnerTouchListener = new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if(mSpinnerDropDown != null && mSpinnerDropDownShowing == false){
            mSpinnerDropDownShowing = true;
            mSpinnerDropDown.setVisibility(View.VISIBLE);
        }
        return false;
    }
};

//Capture the click event on the spinner drop down items
protected OnClickListener spinnerItemClick = new OnClickListener(){

    @Override
    public void onClick(View view) {
        String widget = ((TextView) view.findViewById(android.R.id.text1)).getText().toString();

        if(!widget.equals(SPINNER_INIT_VALUE)){
            if(mCursorAdapter != null){
                Cursor cursor = mCursorAdapter.getCursor();
                if(cursor.moveToFirst()){
                    while(!cursor.isAfterLast()){
                        if(widget.equals(cursor.getString(WidgetQuery.WIDGET_NAME))){

                            ...

                            //Set the spinner to the correct item
                            mSpinnerPosition = cursor.getPosition() + 1;
                            mSpinner.setSelection(mSpinnerPosition);
                            break;
                        }
                        cursor.moveToNext();
                    }
                }
            }
        }

        //Hide the drop down. Not the most elegent solution but it is the only way I could hide/dismiss the drop down
        mSpinnerDropDown = view.getRootView();
        mSpinnerDropDownShowing = false;
        mSpinnerDropDown.setVisibility(View.GONE);
    }
};

private class MyCursorAdapter extends CursorAdapter {

    private final int DISPLACEMENT = 1;
    private final int DEFAULT_ITEM_ID = Integer.MAX_VALUE;

    private Activity mActivity;

    public MyCursorAdapter(Activity activity) {
            super(activity, null, false);
            mActivity = activity;
    }

    //When loading the regular views, inject the defualt item
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(position == 0){
            if(convertView == null){
                convertView = mActivity.getLayoutInflater().inflate(R.layout.list_item_widget, parent, false);
            }
            return getDefaultItem(convertView);
        }
        return super.getView(position - DISPLACEMENT, convertView, parent);
    }

    //When loading the drop down views, set the onClickListener for each view
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent){
        View view = super.getDropDownView(position, convertView, parent);
        view.setOnClickListener(spinnerItemClick);
        return view;
    }

    //The special default item that is being injected
    private View getDefaultItem(View convertView){
        TextView text = (TextView) convertView.findViewById(android.R.id.text1);
        text.setText(SPINNER_INIT_VALUE);
        return convertView;
    }

    @Override
    public long getItemId(int position) {
        if (position == 0) {
            return DEFAULT_ITEM_ID;
        }
        return super.getItemId(position - DISPLACEMENT);
    }

    @Override
    public boolean isEnabled(int position) {
        return position == 0 ? true : super.isEnabled(position - DISPLACEMENT);
    }

    @Override
    public int getViewTypeCount() {
        return super.getViewTypeCount() + DISPLACEMENT;
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return super.getViewTypeCount();
        }

        return super.getItemViewType(position - DISPLACEMENT);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return mActivity.getLayoutInflater().inflate(R.layout.list_item_widget, parent, false);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor){

        if(cursor.isAfterLast()){
            return;
        }

        TextView text = (TextView) view.findViewById(android.R.id.text1);
        String WidgetName = cursor.getString(WidgetQuery.WIDGET_NAME);
        text.setText(WidgetName);
    }
}
}
Malformation answered 19/7, 2013 at 5:7 Comment(0)
D
0

I handle this by using a button instead of a Spinner. I have the sample project up on GitHub.

In the project, i'm displaying both the Spinner and button to show that they indeed look identical. Except the button you can set the initial text to whatever you want.

Here's what the activity looks like:

package com.stevebergamini.spinnerbutton;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Spinner;

public class MainActivity extends Activity {

    Spinner spinner1;
    Button button1;
    AlertDialog ad;
    String[] countries;

    int selected = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        spinner1 = (Spinner) findViewById(R.id.spinner1);
        button1 = (Button) findViewById(R.id.button1);

        countries = getResources().getStringArray(R.array.country_names);

        //  You can also use an adapter for the allert dialog if you'd like
        //  ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, countries);        

        ad = new AlertDialog.Builder(MainActivity.this).setSingleChoiceItems(countries, selected,  
                new  DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            button1.setText(countries[which]);
                            selected = which;
                            ad.dismiss();

                        }}).setTitle(R.string.select_country).create(); 


        button1.setOnClickListener( new OnClickListener(){

            @Override
            public void onClick(View v) {
                ad.getListView().setSelection(selected);
                ad.show();              
            }});

    }

}

NOTE: Yes, I realize that this is dependent on the applied Theme and the look will be slightly different if using Theme.Holo. However, if you're using one of the legacy themes such as Theme.Black, you're good to go.

Deathless answered 17/10, 2013 at 14:42 Comment(0)
P
0

Seems a banal solution but I usually put simply a TextView in the front of the spinner. The whole Xml looks like this. (hey guys, don't shoot me, I know that some of you don't like this kind of marriage):

<FrameLayout
    android:id="@+id/selectTypesLinear"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <Spinner
        android:id="@+id/spinnerExercises"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:entries="@array/exercise_spinner_entries"
        android:prompt="@string/exercise_spinner_prompt"
     />                         
    <TextView
        android:id="@+id/spinnerSelectText"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hey! Select this guy!"
        android:gravity="center"
        android:background="#FF000000" />


</FrameLayout>

Then I hide the TextView when an Item was selected. Obviously the background color of the TextView should be the same as the Spinner. Works on Android 4.0. Don't know on older versions.

Yes. Because the Spinner calls setOnItemSelectedListener at the beginning, the hiding of the textview could be a little bit tricky, but can be done this way:

    Boolean controlTouched;

    exerciseSpinner.setOnTouchListener(new OnTouchListener() {


        @Override
        public boolean onTouch(View v, MotionEvent event) {
            controlTouched = true; // I touched it but but not yet selected an Item.
            return false;
        }

    });
    exerciseSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int arg2, long arg3) {
            if (controlTouched) { // Are you sure that I touched it with my fingers and not someone else  ?
                spinnerSelText.setVisibility(View.GONE);
            }
        }

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

    });
Pledget answered 12/12, 2013 at 0:45 Comment(0)
V
0

for me it worked something like this. has the improvement that only changes the text in SOME options, not in all.

First i take the names of the spinner and create the arrayadapter with a customize view, but it doesn't matter now, the key is override the getView, and inside change the values u need to change. In my case was only the first one, the rest i leave the original

public void rellenarSpinnerCompeticiones(){
        spinnerArrayCompeticiones = new ArrayList<String>();
        for(Competicion c: ((Controlador)getApplication()).getCompeticiones()){
            spinnerArrayCompeticiones.add(c.getNombre());
        }
        //ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this,R.layout.spinner_item_competicion,spinnerArrayCompeticiones);
        ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this, R.layout.spinner_item_competicion, spinnerArrayCompeticiones){
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                final View v = vi.inflate(R.layout.spinner_item_competicion, null);
                final TextView t = (TextView)v.findViewById(R.id.tvCompeticion);
                if(spinnerCompeticion.getSelectedItemPosition()>0){
                    t.setText(spinnerArrayCompeticiones.get(spinnerCompeticion.getSelectedItemPosition()));
                }else{
                    t.setText("Competiciones");
                }
                return v;
            }
        };
        spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinnerCompeticion.setAdapter(spinnerArrayAdapter);
    }
Veolaver answered 20/5, 2014 at 13:10 Comment(0)
B
0
private boolean isFirst = true;
private void setAdapter() {
    final ArrayList<String> spinnerArray = new ArrayList<String>();     
    spinnerArray.add("Select your option");
    spinnerArray.add("Option 1");
    spinnerArray.add("Option 2");
    spin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            TextView tv = (TextView)selectedItemView;
            String res = tv.getText().toString().trim();
            if (res.equals("Option 1")) {
            //do Something
        } else if (res.equals("Option 2")) {
            //do Something else
        }
        }

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

    });
            
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.my_spinner_style,spinnerArray) {
         public View getView(int position, View convertView, ViewGroup parent) {
             View v = super.getView(position, convertView, parent);
             int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, getResources().getDisplayMetrics());                  
             ((TextView) v).setTypeface(tf2);
             ((TextView) v).getLayoutParams().height = height;
             ((TextView) v).setGravity(Gravity.CENTER);
             ((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_SP, 19);
             ((TextView) v).setTextColor(Color.WHITE);
             return v;
         }

         public View getDropDownView(int position, View convertView,
                 ViewGroup parent) {
             if (isFirst) {
                 isFirst = false;
                 spinnerArray.remove(0);
             }
             View v = super.getDropDownView(position, convertView, parent);                  
             ((TextView) v).setTextColor(Color.argb(255, 70, 70, 70));
             ((TextView) v).setTypeface(tf2);
             ((TextView) v).setGravity(Gravity.CENTER);
             return v;
         }
     };
     spin.setAdapter(adapter);
}
Bille answered 7/12, 2014 at 15:37 Comment(0)
S
0

Refer to one of the above answers: https://mcmap.net/q/64175/-how-to-make-an-android-spinner-with-initial-text-quot-select-one-quot

I added my code to fix a little bug. That where no data retrieved..How to show the prompt text..!

Here is my Trick...It works fine with me. !

Try to put your spinner in a Relative_layoutand align a Textview with your spinner and play with the visibility of the Textview (SHOW/HIDE) whenever the adapter of the spinner loaded or empty..Like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:background="#ededed"
android:orientation="vertical">



    <TextView
        android:id="@+id/txt_prompt_from"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:textColor="@color/gray"
        android:textSize="16sp"
        android:layout_alignStart="@+id/sp_from"
        android:text="From"
        android:visibility="gone"/>

    <Spinner
        android:id="@+id/sp_from"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        />

Here is the code:

  txt__from = (TextView) rootView.findViewById(R.id.txt_prompt_from);

call this method after and before spinner adapter loaded and empty.

setPromptTextViewVisibility (); //True or fales 

public void setPromptTextViewVisibility (boolean visible )
{
    if (visible)
    {
        txt_from.setVisibility(View.VISIBLE);
    }
    else
    {
        txt_from.setVisibility(View.INVISIBLE);
    }

}
Standush answered 14/10, 2015 at 19:30 Comment(0)
P
0
String[] listAges = getResources().getStringArray(R.array.ages);

        // Creating adapter for spinner
        ArrayAdapter<String> dataAdapter =
                new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, listAges);

        // Drop down layout style - list view with radio button
        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        // attaching data adapter to spinner
        spinner_age.getBackground().setColorFilter(ContextCompat.getColor(this, R.color.spinner_icon), PorterDuff.Mode.SRC_ATOP);
        spinner_age.setAdapter(dataAdapter);
        spinner_age.setSelection(0);
        spinner_age.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                String item = parent.getItemAtPosition(position).toString();

                if(position > 0){
                    // get spinner value
                    Toast.makeText(parent.getContext(), "Age..." + item, Toast.LENGTH_SHORT).show();
                }else{
                    // show toast select gender
                    Toast.makeText(parent.getContext(), "none" + item, Toast.LENGTH_SHORT).show();
                }
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
Posy answered 28/6, 2016 at 8:20 Comment(0)
S
0
public AdapterView.OnItemSelectedListener instructorSpinnerListener = new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView << ? > adapterView, View view, int i, long l) {
        String selectedInstructorName = adapterView.getItemAtPosition(i).toString();
        if (selectedInstructorName.equals("[Select Instructor]")) {
            instructorSpinnerAdapter.clear();
            for (Offering offering: allOfferingsList)
                instructorSpinnerAdapter.add(offering);
        } else {
            instructorSpinnerAdapter.clear();
        }
    }

    @Override
    public void onNothingSelected(AdapterView<< ? > adapterView) {
        adapterView.setSelection(0);

        // Toast.makeText(getApplicationContext(), "Why?", Toast.LENGTH_SHORT).show();
    }
};
Slemmer answered 5/5, 2018 at 19:53 Comment(0)
F
0

Finally after lots of time, I have created my own solution in 3 lines. I hope this answer help you guys.

in kotlin

3 steps:

  1. add your hint in last item in list:

    val items = arrayListOf("One", "Two", "Three", "Select One")// we will hide last item in dropdown menu
    
  2. override getCount():

    val adapter =
        object: ArrayAdapter<String>(this, R.layout.simple_spinner_dropdown_item, items){
    
            override fun getCount(): Int {
                return super.getCount() -1 //hide last item, count now 3 instead of 4
            }
        }
    
  3. spinner.setSelection(last item position), place this line before spinner.onItemSelectedListener

    spinner.setSelection(3)// 3 is last item "Select One", this will show it as hint 
    
Finicking answered 3/11, 2023 at 6:23 Comment(0)
G
-1

Consider There are N items to be selected.

After adding these N items, add the hint text as (N+1)th item.

Set the selected item to Nth position [(N+1)th item].

In your OnItemSelected Listener, if the selected position is not N, pop the last item and call Adapter.notifyDataSetChanged() and set selected item as the selected position.

Something like this:

    spinner.setItems("Daily", "One time", "Frequency"); // here "Frequency is the hint text"
    spinner.setSelectedIndex(2);

    spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
        @Override
        public void onItemSelected(Spinner view, int position, long id, Object item) {
            if (position != 2) {
                view.setItems("Daily", "One time");
                view.setSelectedIndex(position);
            }else {
                // This item is not a valid selection
            }
        }
    });
Granary answered 15/2, 2016 at 7:37 Comment(0)
A
-2

if you are facing this issue when your items are populates from database-cursor,

the simplest solution that I found in this SO answer:

use UNION in your cursor adapter query and add the additional item with id= -1 to the query result, without really adding it to the DB:

something like:

db.rawQuery("SELECT iWorkerId as _id, nvLastName as name  FROM  Worker
w  UNION  SELECT -1 as _id , '' as name",null);

if the item selected is -1, then it's the default value. Otherwise it's a record from the table.

Ashram answered 24/3, 2014 at 7:7 Comment(0)
P
-4
 ArrayList<String> sizes = new ArrayList<>();

 spinner = (Spinner) findViewById(R.id.spinner_size);

    if (sizes != null && !sizes.isEmpty()) {

        //SORT ArrayList If You Want Data in ASC or DSC Order

        sizes.add("28");
        sizes.add("29");
        sizes.add("31");

        sizes.add("Choose Size"); //adding String at the end of ArrayList
        Collections.reverse(sizes); //Last Item Will Be Shown As A Spinner Title

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, sizes);
        spinner.setAdapter(adapter);

Simply use arraylist.add("Your Data") method to add item at the end of arrayList then just reverse it using Collection.reverse(arrayList) so that the Title be the 1st Item in Spinner. You can also sort the item before adding the data at the end. enter image description here

Potentilla answered 18/6, 2015 at 8:19 Comment(1)
This answer doesn't add anything new to the question. This approach has been already suggested, and adding an identical answer only creates noise. Please read the previous answers before posting a new one.Millet

© 2022 - 2024 — McMap. All rights reserved.