Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set spinner width to current item width

By default the spinner width is set to fit the largest item in the dropdown but I want it to be the same width as the selected item.

<android.widget.Spinner
    android:id="@+id/tab_spinner"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:entries="@array/countries" />

enter image description here

As you can see in the right side image, the spinner is way too long, because of the long item in the list.

How can I resize it to the selected item width ?

like image 415
Nicolas Avatar asked Oct 12 '16 23:10

Nicolas


Video Answer


1 Answers

By default, Spinner will try to measure some of your dropdown views and use the max width found. This happens in Spinner#measureContentWidth(), a protected method of Spinner called in Spinner#onMeasure().

One way to solve the issue is to make sure your SpinnerAdapter#getView() method always uses Spinner#getSelectedItemPosition() for its position argument.

I can think of two possible solutions:

  1. Creating a custom spinner with a wrapper adapter (I prefer this solution)
  2. Or adapting your custom adapter


1. Creating a custom spinner with a wrapper adapter

Make sure to use this in your xml layout, instead of a normal <Spinner>.

Be careful that DynamicWidthSpinner#getAdapter() will return a WrapperSpinnerAdapter; use its getBaseAdapter() method to access to your adapter.

public class DynamicWidthSpinner extends Spinner {

    public DynamicWidthSpinner(Context context) {
        super(context);
    }

    public DynamicWidthSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DynamicWidthSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    public void setAdapter(SpinnerAdapter adapter) {
        super.setAdapter(adapter != null ? new WrapperSpinnerAdapter(adapter) : null);
    }


    public final class WrapperSpinnerAdapter implements SpinnerAdapter {

        private final SpinnerAdapter mBaseAdapter;


        public WrapperSpinnerAdapter(SpinnerAdapter baseAdapter) {
            mBaseAdapter = baseAdapter;
        }


        public View getView(int position, View convertView, ViewGroup parent) {
            return mBaseAdapter.getView(getSelectedItemPosition(), convertView, parent);
        }

        public final SpinnerAdapter getBaseAdapter() {
            return mBaseAdapter;
        }

        public int getCount() {
            return mBaseAdapter.getCount();
        }

        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            return mBaseAdapter.getDropDownView(position, convertView, parent);
        }

        public Object getItem(int position) {
            return mBaseAdapter.getItem(position);
        }

        public long getItemId(int position) {
            return mBaseAdapter.getItemId(position);
        }

        public int getItemViewType(int position) {
            return mBaseAdapter.getItemViewType(position);
        }

        public int getViewTypeCount() {
            return mBaseAdapter.getViewTypeCount();
        }

        public boolean hasStableIds() {
            return mBaseAdapter.hasStableIds();
        }

        public boolean isEmpty() {
            return mBaseAdapter.isEmpty();
        }

        public void registerDataSetObserver(DataSetObserver observer) {
            mBaseAdapter.registerDataSetObserver(observer);
        }

        public void unregisterDataSetObserver(DataSetObserver observer) {
            mBaseAdapter.unregisterDataSetObserver(observer);
        }
    }
}


2. Adapting your custom adapter

Be careful that parent in getView() might not always be a Spinner.

private class SimpleSpinnerAdapter extends BaseAdapter {

    private LayoutInflater mInflater;
    private int mResource;


    public SimpleSpinnerAdapter(Context context, int resource) {
        mInflater = LayoutInflater.from(context);
        mResource = resource;
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(
                mInflater,
                ((Spinner) parent).getSelectedItemPosition(),
                convertView,
                parent,
                mResource);
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(
                mInflater,
                position,
                convertView,
                parent,
                mResource);
    }

    protected View createViewFromResource(LayoutInflater inflater, int position, 
                                          View convertView, ViewGroup parent,
                                          int resource) {
        View view;
        if (convertView == null) {
            view = inflater.inflate(resource, parent, false);
        } else {
            view = convertView;
        }

        bindView(position, view);

        return view;
    }

    protected void bindView(int position, View view) {
        // Bind your view.
    }

    // getCount(), getItem(), and getItemId() methods.
}
like image 50
jpmcosta Avatar answered Oct 16 '22 12:10

jpmcosta