4

I have a Spinner on my Activity. I use an ArrayList and a custom SpinnerAdapter to populate the list that pops up when the Spinner is pressed.

My problem is the way the Spinner looks on the Activity when it is not pressed. It is all gray. No text is visible. Even after I press the spinner and then choose an item from the resulting list, the Spinner does not populate with text.

Also, when I select an item from the Spinner and then print the selected item position, it prints -1. Many have commented that there is no list of data attached to my spinner, but there obviously is. How else could I press on the Spinner and then choose from a resulting list?

        // This sets up the adapter and the arraylist that contains the data
            private void setUpAdapter() {
                mData = new ArrayList<MyData>();
                mAdapter = new MyAdapter(mData);
                mSpinner.setAdapter(mAdapter);

                mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
                    public void onItemSelected(AdapterView<?> parent,
                            View view, int pos, long id) {
                            MyData g = (MyData) parent.getItemAtPosition(pos);
                            // TODO
                        }

                        public void onNothingSelected(AdapterView parent) {
                          // Do nothing.
                        }
                });
            }


    // this populates the arraylist that is attached to the spinner's adapter
// it is called once an AsyncTask finishes pulling data from a local database
            private void populateSpinner(ArrayList<MyData> result) {
                if (result != null) {
                    if (mData == null) {
                        mData = new ArrayList<MyData>();
                    }
                    else {
                        mData.clear();
                    }

                    for (int index = 0; index < result.size(); index++) {
                        mData.add(result.get(index));
                    }

                    mSpinner.setSelected(0);
                }
            }




    // this is the adapter for the spinner
            private class MyAdapter implements SpinnerAdapter {

                ArrayList<MyData> data;

                public MyAdapter(ArrayList<MyData> data){
                    this.data = data;
                }

                @Override
                public int getCount() {
                    return data.size();
                }

                @Override
                public Object getItem(int position) {
                    return data.get(position);
                }

                @Override
                public long getItemId(int position) {
                    return position;
                }

                @Override
                public int getItemViewType(int position) {
                    return android.R.layout.simple_spinner_dropdown_item;
                }

                @Override
                public View getView(int position, View convertView, ViewGroup parent) {
                    TextView v = new TextView(getApplicationContext());
                    v.setTextColor(Color.BLACK);
                    v.setText(data.get(position).getName());
                    v.setPadding(0, 20, 0, 20);
                    return v;
                }

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

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

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

                @Override
                public void registerDataSetObserver(DataSetObserver observer) {
                    // TODO Auto-generated method stub
                }

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

                @Override
                public View getDropDownView(int position, View convertView, ViewGroup parent) {
                    return this.getView(position, convertView, parent);
                }
            }


<Spinner
    android:id="@+id/my_spinner"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
Andrew
  • 20,756
  • 32
  • 99
  • 177

4 Answers4

1
When I select an item from the Spinner and then print the selected item position, it prints -1

This is because you are referencing BLANK list

mData = new ArrayList<MyData>();
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);

Set spinner adapter in onPostExecute() of AsynTask.

@Override
protected void onPreExecute() {
        mData = new ArrayList<MyData>();
        super.onPreExecute();
}

@Override
protected Void doInBackground(String... params) {
        //gets "result" to fill mData
        return null;
}

@Override
protected void onPostExecute(Void result) {
    setUpAdapter();
}


private void setUpAdapter() {
    if (result != null) {
          if (mData == null) {
                 mData = new ArrayList<MyData>();
           }
           else {
                 mData.clear();
           }

           for (int index = 0; index < result.size(); index++) {
                 mData.add(result.get(index));
           }

            mAdapter = new MyAdapter(mData);
            mSpinner.setAdapter(mAdapter);
            mSpinner.setSelected(0);

            mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
                public void onItemSelected(AdapterView<?> parent,
                        View view, int pos, long id) {
                        MyData g = (MyData) parent.getItemAtPosition(pos);
                        // TODO
                    }

                    public void onNothingSelected(AdapterView parent) {
                      // Do nothing.
                    }
            });
        }
Mohammed Azharuddin Shaikh
  • 41,633
  • 14
  • 96
  • 115
  • I'm not sure how I am referencing a null list. Obviously the spinner is populating with items. Or do I misunderstand what you're saying? I do this in a lot of other places with ListView. I throw an empty (but instantiated) ArrayList into the Adapter, and then I copy data into the Adapter when I get it. – Andrew May 22 '12 at 15:48
  • I moved my setAdapter call to the post execute of the AsyncTask and there was no change in behavior. – Andrew May 22 '12 at 15:50
  • `null` I mean blank(initialized but no data), implement just like i had shown you. – Mohammed Azharuddin Shaikh May 22 '12 at 17:24
  • Yes, when I originally initialize the Adapter, the ArrayList is empty. When the AsyncTask finishes retrieving the data from the database, it is copied into the ArrayList. I don't think this should matter, and, indeed, the data shows up in the Spinner. – Andrew May 22 '12 at 18:11
  • I also tried simply using an ArrayAdapter full of MyData objects (I created a toString method in MyData so the Spinner would know what to display). Again, the data shows up in the spinner, but when I select something there is no text on the Spinner and getSelectedItemPosition returns -1. – Andrew May 22 '12 at 18:12
  • after setting the adapter use `setSelection(0)` immediately. – Mohammed Azharuddin Shaikh May 29 '12 at 04:24
1

Use Activity context instead of the Application context for your spinner. See documentation of getApplicationContext() api to understand its proper usage.

Pass the activity context to MyAdapter and use it in creating the TextView's in getView callback.

mAdapter = new MyAdapter(mData, this); // this is activity context.

In MyAdapter :

public MyAdapter(ArrayList<MyData> data, Context context){
     this.data = data;
     mContext = context;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
     TextView v = new TextView(mContext);
     v.setTextColor(Color.BLACK);
     v.setBackgroundColor(Color.WHITE);
     v.setText(data.get(position).getName());
     v.setPadding(0, 20, 0, 20);
     return v;
}
Ron
  • 24,175
  • 8
  • 56
  • 97
  • I agree that this is a mistake, and I have rectified it, but my problem still persists. No text is showing on the Spinner after selecting an item and calling getSelectedItemPosition returns -1 still. – Andrew May 23 '12 at 19:27
0

You can set static sizes using the xml attribute android:layout_height. Using dp unit instead of px is recommended for multiple screen compatibility.

As for the text, try to use android:prompt attribute in your Spinner xml. For the color I'm guessing it's like other widgets, just use android:textColor

Comic Sans MS Lover
  • 1,729
  • 5
  • 26
  • 52
  • As amp said, the Spinner does not have a textColor attribute. I'm not sure why no text is visible, but it's making space for the text because the height dimension changes based on what string is selected. Also, I know I can set a static height using the layout_height attribute, but I was hoping for something like a singleline attribute. – Andrew May 18 '12 at 20:08
  • @amp You are right... unfortunately it seems that setting spinner text color is more complicated than it seems. see this: http://stackoverflow.com/questions/6159113/android-where-is-the-spinner-widgets-text-color-attribute-hiding – Comic Sans MS Lover May 18 '12 at 20:26
  • About the height issue, I don't think there's another solution. Maybe you could implement Spinner class, but if you don't have a really good reason to fix the height (besides looking good at the layout), I think this is not viable. Of course this is up to you. – Comic Sans MS Lover May 18 '12 at 20:30
  • @Andrew Maybe the problem is `` attributes... Add the code xml for this widget please. – amp May 18 '12 at 21:05
  • Done. There's not much to it. I did specify an exact height for the Spinner. I just can't figure out why the text isn't showing. – Andrew May 18 '12 at 21:19
  • In case it's relevant, when I choose an item from the dropdown list and then hit a breakpoint to check the selected position, it returns -1. – Andrew May 21 '12 at 19:12
0

THIS code is WORKING, the spinner correctly display the field, however i must say maybe it is not 100% perfect, cause for some reason im unable to leave blank the initial value of the field, it has by default the value of item 0. package com.cccheck;

public class OneCheckActivity extends Activity {

LayoutInflater factory;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.spinner_view);
    ArrayList tdata = new ArrayList<MyData>();
    MyData mdata =new MyData();
    mdata.setName("");
    mdata.setData("-1");
    MyData ndata =new MyData();
    ndata.setName("ciao belluzzo");
    ndata.setData("1");
    tdata.add(mdata);
    tdata.add(ndata);
    mdata= new MyData();
    mdata.setName("vai alla fnac");
    mdata.setData("2");
    tdata.add(mdata);
    mSpinner = (Spinner) findViewById(R.id.my_spinner);
    factory = LayoutInflater.from(this);

    populateSpinner(tdata);

    setUpAdapter();
    mSpinner.setSelected(false);
    try  {
        mAdapter.notify();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    //mAdapter.registerDataSetObserver(new MyObserver());
}
ArrayList<MyData> mData;
MyAdapter mAdapter = new MyAdapter(null);
Spinner mSpinner;
// This sets up the adapter and the arraylist that contains the data
private void setUpAdapter() {
    mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent,
                View view, int pos, long id) {
                MyData g = (MyData) parent.getItemAtPosition(pos);
                // TODO
                Toast.makeText(OneCheckActivity.this , "selected item : " + pos + ", value: " + g.getData(),Toast.LENGTH_LONG).show();

            }
        @Override
            public void onNothingSelected(AdapterView parent) {
              // Do nothing.
            }

    });
}


  // this populates the arraylist that is attached to the spinner's adapter
  //it is called once an AsyncTask finishes pulling data from a local database
private void populateSpinner(ArrayList<MyData> result) {
    if (result != null) {
        if (mData == null) {
            mData = new ArrayList<MyData>();
        }
        else {
            mData.clear();
        }

        for (int index = 0; index < result.size(); index++) {
            mData.add(result.get(index));
        }
        mAdapter = new MyAdapter(mData);

        mSpinner.setAdapter(mAdapter);
    }
}




// this is the adapter for the spinner
private class MyAdapter implements SpinnerAdapter {

    ArrayList<MyData> data;

    public MyAdapter(ArrayList<MyData> data){
        this.data = data;
    }
    public void updateData(ArrayList<MyData> data){
        this.data = data;
    }

    @Override
    public int getCount() {
        return data.size(); 
        }

    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getItemViewType(int position) {
        return android.R.layout.simple_spinner_dropdown_item;
    }

    @Override
    public LinearLayout getView(int position, View convertView, ViewGroup parent) {
        LinearLayout pv = (LinearLayout)(factory.inflate(R.layout.spinner_item, null));
        TextView tv = (TextView) pv.findViewById(R.id.textviewid);
        tv.setTextColor(Color.BLACK);
        MyData item = data.get(position);
        tv.setText( item.getName() + " - " + item.getData() + " ");
        tv.setPadding(0, 20, 0, 20);
        return pv;
    }

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

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

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

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        // TODO Auto-generated method stub

    }

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

    @Override
    public LinearLayout getDropDownView(int position, View convertView, ViewGroup parent) {
        if (convertView instanceof LinearLayout) System.out.println("%%%%%%%%%%%%%%55555 hai ragione");
        return this.getView(position, convertView, parent);
    }
}




}

use this as layout for spinner_item.xml

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

<TextView 
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="28px"
android:id="@+id/textviewid"
/>

</LinearLayout>
  • This is very similar to hotveryspicy's implementation, which does not solve my issue. – Andrew Jun 06 '12 at 18:59
  • if you look beyond your nose, you'll see that the code that I posted so patiently DOES solve your problem, but you're too arrogant to accept it –  Jun 11 '12 at 18:30