Search code examples
androiddropdownword-wrapautocompletetextview

Can I setup my an Android drop-down list layout to wrap lengthy items?


Problem - Trying to do: I've been unsuccessfully trying to get lengthy items in a drop down list to wrap. I really wasn't sure it is possible. I have a drop down list with question options, which can be long in a few cases.

What I have tried: I've created a custom TextView layout for the adapter used to populate the AutoCompleteTextView. I've tried the usual and combinations of wrap-content, android:singleLine=false, android:lines="2" without any success. I really thought someone has probably tried this before

Layout

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:minHeight="25dp"
          android:padding="5dp"
          android:singleLine="false"
          style="@style/MyDropDownTheme"
          android:id="@+id/text1" android:hint="@string/hint_type">
</TextView>

ArrayAdapter

    ArrayAdapter questions = new ArrayAdapter<>(context, R.layout.custom_drowdown_list_wrap, orgQuestions);
    question.setAdapter(questions);

Solution

  • For that you would need a custom Spinner and it's Adapter. Something like this will help you.

    class DynamicSizeSpinner : androidx.appcompat.widget.AppCompatSpinner {
    
        var inOnMeasure = false
            private set
    
        constructor(context: Context) : super(context)
        constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
        constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            inOnMeasure = true
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            inOnMeasure = false
        }
    }
    
    class SpinnerArrayAdapter(context: Context, @LayoutRes layout: Int, val entries: Map<String, String>) : ArrayAdapter<String>(context, layout, entries.keys.toList()) {
    
        override fun isEnabled(position: Int): Boolean {
            return position != 0
        }
    
        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
            val selectedItemPosition = when (parent) {
                is AdapterView<*> -> parent.selectedItemPosition
                is DynamicSizeSpinner -> parent.selectedItemPosition
                else -> position
            }
            return makeLayout(selectedItemPosition, convertView, parent, R.layout.simple_spinner_dropdown_item_custom)
        }
    
        override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
            return makeLayout(position, convertView, parent, R.layout.simple_spinner_dropdown_item_custom)
        }
    
        private fun makeLayout(position: Int, convertView: View?, parent: ViewGroup, layout: Int): View {
            val tv = convertView ?: LayoutInflater.from(context).inflate(layout, parent, false)
            if (position != -1) {
                (tv as? TextView)?.text = entries.keys.toList()[position]
            }
            return tv
        }
    }
    

    I'm using Map for the entries you can use a List or an Array