Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spinner does not wrap text -- is this an Android bug?

If the text of a Spinner item is too long to fit into a single line, the text is not wrapped but cut off. This is only the case for API level >= 11. Here are screenshots of Android 4.2.2 (left) which shows the wrong behavior and Android 2.3.3 (right) where it looks as expected.

android:singleLine="false" simply gets ignored here. So as all other tries like android:lines, android:minLines, etc. The TextView somehow seems to be much wider than the window width.

I saw other people having the same problem, but no one could find a solution. So, is this a system bug? I don't think this inconsistency between the OS versions can be intended.


Please note:

There were some answers suggesting relatively simple solutions.

  • Writing a custom Adapter and overriding getView() as well as getDropDownView(). This is not the solution here, because at this point, there is still the original problem: How does the layout have to look like to handle proper line wrapping?

  • Wrapping the TextView of the drop down view into a parent ViewGroup. Does not work with android:layout_width="match_parent" because the width of the parent strangely seems to be unlimited.

  • Giving the drop down view a fixed width. This is not suitable with the different widths the Spinner can have.

  • And of course, no solution is to manually insert \ns anywhere into the text.


Reproduce with the following code:

UPDATE: I also uploaded this as a sample project on GitHub: Download

/res/values/arrays.xml:

<string-array name="items">     <item>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</item>     <item>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est.</item> </string-array> 

/res/layout/spinner_item.xml:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"     android:id="@android:id/text1"     style="?android:attr/spinnerDropDownItemStyle"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:ellipsize="none"     android:minHeight="?android:attr/listPreferredItemHeight"     android:singleLine="false" /> 

Set Adapter:

spinner.setAdapter(ArrayAdapter.createFromResource(this,             R.array.items,             R.layout.spinner_item)); 
like image 221
Matthias Robbers Avatar asked Jan 03 '13 12:01

Matthias Robbers


People also ask

What is the difference between spinner and ListView in android?

Spinners provide a quick way to select one value from a set. In the default state, a spinner shows its currently selected value. Touching the spinner displays a dropdown menu with all other available values, from which the user can select a new one. ListView is a view group that displays a list of scrollable items.

How can we check whether a spinner is open or not in android?

We can user onClickListner for spinner. Since spinner open when we click(tap) on it. And to chcek where the spinner is open or not we can use onItemSelectedListner callbacks. Tell me if you want further code example.


1 Answers

In holo theme spinner by default uses dropdown mode. And all moves with overriding default styles just move to switching spinner mode to dialog mode which succesfully wraps multiline text as in api 11. Instead you can create spinner with new Spinner(context, Spinner.MODE_DIALOG) or in xml: android:spinnerMode="dialog". But it's not resolve the problem, because it's dialog, not dropdown.

I have found another solution for this trouble: Override getDropDownView method in ArrayAdapter and put setSingleLine(false) in post method of view. So when view completely created it wraps the text to appropriate lines.

@Override public View getDropDownView(final int position, View convertView, ViewGroup parent) {     if (convertView == null) {         convertView = new TextView(_context);     }      TextView item = (TextView) convertView;     item.setText("asddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");     final TextView finalItem = item;     item.post(new Runnable() {         @Override         public void run() {             finalItem.setSingleLine(false);         }     });     return item; } 

UPDATE:

And here is another answer.

Manually wrap listview in PopupWindow and show it under TextView on click and hide it on listItem click.

Simple implementation just to show idea:

public class MySpinner extends TextView {     private PopupWindow _p;     private ListView _lv;     public MySpinner(Context context) {         super(context);         init();     }     public MySpinner(Context context, AttributeSet attributeSet){         super(context, attributeSet);         init();     }      private void init(){         setBackgroundResource(R.drawable.spinner_background);         final List<String> list = new ArrayList<String>();         list.add("Very long text AAAAAAAAAAAAAAAA");         list.add("1 Very long text AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");         list.add("2 Very long text A");         list.add("3 Very long text AAAAAAAAA");          setMinimumWidth(100);         setMaxWidth(200);          _lv = new ListView(getContext());         _lv.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.simple_list_item_1, list));         _lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {             @Override             public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {                 _p.dismiss();                 setText(list.get(i));             }         });          setOnClickListener(new OnClickListener() {             @Override             public void onClick(View view) {                  _p = new PopupWindow(getContext());                 _p.setContentView(_lv);                 _p.setWidth(getWidth());                 _p.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);                 _p.setTouchable(true);                 _p.setFocusable(true);                 _p.setOutsideTouchable(true);                 _p.showAsDropDown(view);             }         });     } } 
like image 154
Kolchuga Avatar answered Sep 24 '22 13:09

Kolchuga