6

I found this workaround for adding a hint to a dropdown spinner. It looked promising, but instead of getting my desired strings to show in the spinner, I'm getting something that looks like my package name (can't see the full name).
enter image description here

@IsaacCisneros created new SpinnerItem and MySpinnerAdapter classes. I implemented his new classes exactly. My implementation looks like this:

ArrayList<SpinnerItem> credValues = new ArrayList<SpinnerItem>();
         credValues.add(new SpinnerItem("3.0",false));
         credValues.add(new SpinnerItem("Credit", true));

         MySpinnerAdapter adapter_cred = new MySpinnerAdapter(this.getActivity(),
                 android.R.layout.simple_spinner_item, credValues);
         adapter_cred.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

         Spinner spinCred = (Spinner)rootView.findViewById(R.id.cred_spinner);
         spinCred.setAdapter(adapter_cred);
         spinCred.setSelection(credValues.size() - 1);

And his looks like this:

ArrayList<SpinnerItem> items = new ArrayList<SpinnerItem>();
    items.add(new SpinnerItem("Item 1", false));
    items.add(new SpinnerItem("Item 2", false));
    items.add(new SpinnerItem("HINT", true)); // Last item 

    MySpinnerAdapter adapter = new MySpinnerAdapter(this, android.R.layout.simple_spinner_item, items);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);
    spinner.setSelection(items.size() - 1);

So why is mine acting weird? The context for my code is the onCreateView of my AddItemFragment within my activity. What am I referencing wrong? Thanks!


EDIT: The adapter class code was requested...

class SpinnerItem {
    private final String text;
    private final boolean isHint;

    public SpinnerItem(String strItem, boolean flag) {
        this.isHint = flag;
        this.text = strItem;
    }

    public String getItemString() {
        return text;
    }

    public boolean isHint() {
        return isHint;
    }
}

class MySpinnerAdapter extends ArrayAdapter<SpinnerItem> {
    public MySpinnerAdapter(Context context, int resource, List<SpinnerItem> objects) {
        super(context, resource, objects);
    }

    @Override
    public int getCount() {
        return super.getCount() - 1; // This makes the trick: do not show last item
    }

    @Override
    public SpinnerItem getItem(int position) {
        return super.getItem(position);
    }

    @Override
    public long getItemId(int position) {
        return super.getItemId(position);
    }
}
Community
  • 1
  • 1
NSouth
  • 5,067
  • 7
  • 48
  • 83
  • It would seem that the HINT item is set in the Adapter. Please post the relevant code from that class. – Mike M. Apr 03 '14 at 02:31
  • @MikeM. I added the adapter code. The hint is just a boolean. ALL of my dropdown items look the same. They are the package name (I don't know how they end). I declare the SpinnerItem in the MySpinnerAdapter class, if that matters. – NSouth Apr 03 '14 at 02:43

3 Answers3

8

The reason is because you have not overridden the getView() method of the adapter. Because of this, it uses the default implementation which looks like this:

T item = getItem(position);

if (item instanceof CharSequence) {
    text.setText((CharSequence)item);
} 
else {
    text.setText(item.toString());
}

In your SpinnerItem you do not have a toString() method, so it uses the default value (which is what you see as the package name)

One way to fix this would be by adding a toString() method to your SpinnerItem:

class SpinnerItem {
    private final String text;
    private final boolean isHint;

    public SpinnerItem(String strItem, boolean flag) {
        this.isHint = flag;
        this.text = strItem;
    }

    public String getItemString() {
        return text;
    }

    public boolean isHint() {
        return isHint;
    }

    @Override
    public String toString() {
        return text;
    }
}

If you want more control, such as different color for the hint text etc. I recommend you implement the getView() method on your own.

Amulya Khare
  • 7,718
  • 2
  • 23
  • 38
4

Probably your adapter extends android.widget.ArrayAdapter. By default in implementation of ArrayAdapter - in android source code - as Amulya Khare said, the getView method, gains value of text view through

T item = getItem(position);
if (item instanceof CharSequence) {
   text.setText((CharSequence)item);
} 
else {
   text.setText(item.toString());
}

By default each class that inherits from Object class - like your SpinneItem class - returns package name through toString method. so you can override toString of SpinnerItem or override getView of MySpinnerAdapter.

4

In your adapter add these in constructor

private Context mContext;
private int layoutId;
private List<SpinnerItem> dataList;
public MySpinnerAdapter(Context context, int resource, List<SpinnerItem> objects) {
        super(context, resource, objects);
        this.mContext = context;
        this.layoutId = resource;
        this.dataList = objects;
    }

you need to set data in Spinner using getDropDownView() and getView() no need to implement getCount() , getItem() and getItemId() because in ArrayAdapter row is created by super call of constructor.

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        ViewHolder viewHolder;
        if(convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(layoutId, null);
            viewHolder = new ViewHolder();
            viewHolder.itemNameTxtView = (TextView) convertView.findViewById(R.id.ur_txtview_id);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        String itemName = "";
        SpinnerItem spinnerItem = (SpinnerItem) dataList.get(position);
            itemName = spinnerItem.getItemString();

        viewHolder.itemNameTxtView.setText(itemName);
        return convertView;
    }

@Override
public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        ViewHolder viewHolder;
        if(convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(layoutId, null);
            viewHolder = new ViewHolder();
            viewHolder.itemNameTxtView = (TextView) convertView.findViewById(R.id.ur_txtview_id);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        String itemName = "";
        SpinnerItem spinnerItem = (SpinnerItem) dataList.get(position);
            itemName = spinnerItem.getItemString();

        viewHolder.itemNameTxtView.setText(itemName);
        return convertView;
    }


    private class ViewHolder {
        TextView itemNameTxtView;
    }
Kaushik
  • 6,150
  • 5
  • 39
  • 54
  • Thanks @kaushik for the reply. The toString() solution that others posted worked great, except I want to be able to set the text color to look like a hint. I tried your implementation, but my screen crashes upon loading. Are both methods meant to have the exact same code? I'm also not sure what I should be putting in the "ur_txtview_id" field. Btw, I'm getting a NullPointerException at the viewHolder.itemNameTxtView.setText(itemname) line of getView. – NSouth Apr 03 '14 at 19:31
  • `"ur_txtview_id"` is textview's id u have used to populate the spinner `Are both methods meant to have the exact same code?` **yes** – Kaushik Apr 04 '14 at 05:30