'Android Spinner -- how to size to currently selected item?
It appears that a spinner is sized to the longest item given in its adapter. This is a good behavior for the majority of cases, but it is undesirable in my particular case.
Is this possible to turn this off? My guess is no, by looking at Spinner.onMeasure() in the source, but figured I'd ask.
Solution 1:[1]
I achieved this now by subclassing Spinner:
public class SpinnerWrapContent extends IcsSpinner {
private boolean inOnMeasure;
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
inOnMeasure = true;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
inOnMeasure = false;
}
public boolean isInOnMeasure() {
return inOnMeasure;
}
}
Then in my SpinnerAdapter's getView(), I used the currently selected position if I am called from onMeasure():
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView != null)
view = convertView;
else {
int fixedPosition = (spinner.isInOnMeasure() ? spinner.getSelectedItemPosition() : position);
// Here create view for fixedPosition
}
return view;
}
Solution 2:[2]
This worked for me. Important part is this. Put the below above code is your adapter and use selectedItemPosition for selecting text from objects array.
int selectedItemPosition = position;
if (parent instanceof AdapterView) {
selectedItemPosition = ((AdapterView) parent)
.getSelectedItemPosition();
}
Example is given below.
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
final View spinnerCell;
if (convertView == null) {
// if it's not recycled, inflate it from layout
spinnerCell = inflater.inflate(R.layout.layout_spinner_cell, parent, false);
} else {
spinnerCell = convertView;
}
int selectedItemPosition = position;
if (parent instanceof AdapterView) {
selectedItemPosition = ((AdapterView) parent)
.getSelectedItemPosition();
}
TextView title = (TextView) spinnerCell.findViewById(R.id.spinnerTitle);
title.setText(titles[selectedItemPosition]);
return spinnerCell;
}
If you need an explanation follow this link: http://coding-thoughts.blogspot.in/2013/11/help-my-spinner-is-too-wide.html
Solution 3:[3]
If anyone is looking for a Kotlin Answer, here is how you do it.
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: List<String>) : ArrayAdapter<String>(context, layout, entries) {
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 view = convertView ?: LayoutInflater.from(context).inflate(layout, parent, false)
if (position != -1) {
(view as? TextView)?.text = entries[position]
}
return view
}
}
Use the DynamicSizeSpinner as you would use the default Spinner in your XML/JAVA/Kotlin code.
P.S don't forget to read the original article.
Solution 4:[4]
If your're looking to just make the Spinner shorter, it's an easy fix.
Generally you can change the height and width of any view by giving it a weight, or setting it's layout_width and layout_height:
<Spinner
android:id="@+id/shortenedSpinner"
android:layout_width="100dp"
android:layout_height="50dp" />
This will force the spinner to be shorter
If you want the drop down view to be shorter, that is different. In this case, I suppose you could supply a custom row in the spinner adapter's getDropDownView() method which has the same changes as stated above.
Solution 5:[5]
Here is more elegant almost one-liner solution:
class ResizingArrayAdapter<T>(context: Context, @LayoutRes layoutResId: Int, @IdRes textViewResourceId: Int, objects: List<T>) :
ArrayAdapter<T>(context, layoutResId, textViewResourceId, objects) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View =
super.getView(if (parent is AdapterView<*>) parent.selectedItemPosition else position, convertView, parent)
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Tom anMoney |
| Solution 2 | Vineet Ashtekar |
| Solution 3 | OhhhThatVarun |
| Solution 4 | Shellum |
| Solution 5 |
