FileDocCategorySizeDatePackage
Spinner.javaAPI DocAndroid 5.1 API41624Thu Mar 12 22:22:10 GMT 2015android.widget

Spinner

public class Spinner extends AbsSpinner implements android.content.DialogInterface.OnClickListener
A view that displays one child at a time and lets the user pick among them. The items in the Spinner come from the {@link Adapter} associated with this view.

See the Spinners guide.

attr
ref android.R.styleable#Spinner_dropDownSelector
attr
ref android.R.styleable#Spinner_dropDownWidth
attr
ref android.R.styleable#Spinner_gravity
attr
ref android.R.styleable#Spinner_popupBackground
attr
ref android.R.styleable#Spinner_prompt
attr
ref android.R.styleable#Spinner_spinnerMode
attr
ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
attr
ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset

Fields Summary
private static final String
TAG
private static final int
MAX_ITEMS_MEASURED
public static final int
MODE_DIALOG
Use a dialog window for selecting spinner options.
public static final int
MODE_DROPDOWN
Use a dropdown anchored to the Spinner for selecting spinner options.
private static final int
MODE_THEME
Use the theme-supplied value to select the dropdown mode.
private android.widget.ListPopupWindow.ForwardingListener
mForwardingListener
Forwarding listener used to implement drag-to-open.
private SpinnerPopup
mPopup
private DropDownAdapter
mTempAdapter
int
mDropDownWidth
private int
mGravity
private boolean
mDisableChildrenWhenDisabled
private android.graphics.Rect
mTempRect
Constructors Summary
public Spinner(android.content.Context context)
Construct a new spinner with the given context's theme.

param
context The Context the view is running in, through which it can access the current theme, resources, etc.


                                            
       
        this(context, null);
    
public Spinner(android.content.Context context, int mode)
Construct a new spinner with the given context's theme and the supplied mode of displaying choices. mode may be one of {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN}.

param
context The Context the view is running in, through which it can access the current theme, resources, etc.
param
mode Constant describing how the user will select choices from the spinner.
see
#MODE_DIALOG
see
#MODE_DROPDOWN

        this(context, null, com.android.internal.R.attr.spinnerStyle, mode);
    
public Spinner(android.content.Context context, android.util.AttributeSet attrs)
Construct a new spinner with the given context's theme and the supplied attribute set.

param
context The Context the view is running in, through which it can access the current theme, resources, etc.
param
attrs The attributes of the XML tag that is inflating the view.

        this(context, attrs, com.android.internal.R.attr.spinnerStyle);
    
public Spinner(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)
Construct a new spinner with the given context's theme, the supplied attribute set, and default style attribute.

param
context The Context the view is running in, through which it can access the current theme, resources, etc.
param
attrs The attributes of the XML tag that is inflating the view.
param
defStyleAttr An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.

        this(context, attrs, defStyleAttr, 0, MODE_THEME);
    
public Spinner(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int mode)
Construct a new spinner with the given context's theme, the supplied attribute set, and default style. mode may be one of {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN} and determines how the user will select choices from the spinner.

param
context The Context the view is running in, through which it can access the current theme, resources, etc.
param
attrs The attributes of the XML tag that is inflating the view.
param
defStyleAttr An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.
param
mode Constant describing how the user will select choices from the spinner.
see
#MODE_DIALOG
see
#MODE_DROPDOWN

        this(context, attrs, defStyleAttr, 0, mode);
    
public Spinner(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes, int mode)
Construct a new spinner with the given context's theme, the supplied attribute set, and default style. mode may be one of {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN} and determines how the user will select choices from the spinner.

param
context The Context the view is running in, through which it can access the current theme, resources, etc.
param
attrs The attributes of the XML tag that is inflating the view.
param
defStyleAttr An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.
param
defStyleRes A resource identifier of a style resource that supplies default values for the view, used only if defStyleAttr is 0 or can not be found in the theme. Can be 0 to not look for defaults.
param
mode Constant describing how the user will select choices from the spinner.
see
#MODE_DIALOG
see
#MODE_DROPDOWN

        super(context, attrs, defStyleAttr, defStyleRes);

        final TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.Spinner, defStyleAttr, defStyleRes);

        if (mode == MODE_THEME) {
            mode = a.getInt(com.android.internal.R.styleable.Spinner_spinnerMode, MODE_DIALOG);
        }
        
        switch (mode) {
        case MODE_DIALOG: {
            mPopup = new DialogPopup();
            break;
        }

        case MODE_DROPDOWN: {
            final DropdownPopup popup = new DropdownPopup(context, attrs, defStyleAttr, defStyleRes);

            mDropDownWidth = a.getLayoutDimension(
                    com.android.internal.R.styleable.Spinner_dropDownWidth,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            popup.setBackgroundDrawable(a.getDrawable(
                    com.android.internal.R.styleable.Spinner_popupBackground));

            mPopup = popup;
            mForwardingListener = new ForwardingListener(this) {
                @Override
                public ListPopupWindow getPopup() {
                    return popup;
                }

                @Override
                public boolean onForwardingStarted() {
                    if (!mPopup.isShowing()) {
                        mPopup.show(getTextDirection(), getTextAlignment());
                    }
                    return true;
                }
            };
            break;
        }
        }

        mGravity = a.getInt(com.android.internal.R.styleable.Spinner_gravity, Gravity.CENTER);

        mPopup.setPromptText(a.getString(com.android.internal.R.styleable.Spinner_prompt));

        mDisableChildrenWhenDisabled = a.getBoolean(
                com.android.internal.R.styleable.Spinner_disableChildrenWhenDisabled, false);

        a.recycle();

        // Base constructor can call setAdapter before we initialize mPopup.
        // Finish setting things up if this happened.
        if (mTempAdapter != null) {
            mPopup.setAdapter(mTempAdapter);
            mTempAdapter = null;
        }
    
Methods Summary
public intgetBaseline()

        View child = null;

        if (getChildCount() > 0) {
            child = getChildAt(0);
        } else if (mAdapter != null && mAdapter.getCount() > 0) {
            child = makeView(0, false);
            mRecycler.put(0, child);
        }

        if (child != null) {
            final int childBaseline = child.getBaseline();
            return childBaseline >= 0 ? child.getTop() + childBaseline : -1;
        } else {
            return -1;
        }
    
public intgetDropDownHorizontalOffset()
Get the configured horizontal offset in pixels for the spinner's popup window of choices. Only valid in {@link #MODE_DROPDOWN}; other modes will return 0.

return
Horizontal offset in pixels
attr
ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset

        return mPopup.getHorizontalOffset();
    
public intgetDropDownVerticalOffset()
Get the configured vertical offset in pixels for the spinner's popup window of choices. Only valid in {@link #MODE_DROPDOWN}; other modes will return 0.

return
Vertical offset in pixels
attr
ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset

        return mPopup.getVerticalOffset();
    
public intgetDropDownWidth()
Get the configured width of the spinner's popup window of choices in pixels. The returned value may also be {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} meaning the popup window will match the width of the Spinner itself, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} to wrap to the measured size of contained dropdown list items.

return
Width in pixels, WRAP_CONTENT, or MATCH_PARENT
attr
ref android.R.styleable#Spinner_dropDownWidth

        return mDropDownWidth;
    
public intgetGravity()
Describes how the selected item view is positioned. The default is determined by the current theme.

return
A {@link android.view.Gravity Gravity} value

        return mGravity;
    
public android.graphics.drawable.DrawablegetPopupBackground()
Get the background drawable for the spinner's popup window of choices. Only valid in {@link #MODE_DROPDOWN}; other modes will return null.

return
background Background drawable
attr
ref android.R.styleable#Spinner_popupBackground

        return mPopup.getBackground();
    
public java.lang.CharSequencegetPrompt()

return
The prompt to display when the dialog is shown

        return mPopup.getHintText();
    
voidlayout(int delta, boolean animate)
Creates and positions all views for this Spinner.

param
delta Change in the selected position. +1 means selection is moving to the right, so views are scrolling to the left. -1 means selection is moving to the left.

        int childrenLeft = mSpinnerPadding.left;
        int childrenWidth = mRight - mLeft - mSpinnerPadding.left - mSpinnerPadding.right;

        if (mDataChanged) {
            handleDataChanged();
        }

        // Handle the empty set by removing all views
        if (mItemCount == 0) {
            resetList();
            return;
        }

        if (mNextSelectedPosition >= 0) {
            setSelectedPositionInt(mNextSelectedPosition);
        }

        recycleAllViews();

        // Clear out old views
        removeAllViewsInLayout();

        // Make selected view and position it
        mFirstPosition = mSelectedPosition;

        if (mAdapter != null) {
            View sel = makeView(mSelectedPosition, true);
            int width = sel.getMeasuredWidth();
            int selectedOffset = childrenLeft;
            final int layoutDirection = getLayoutDirection();
            final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
            switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                case Gravity.CENTER_HORIZONTAL:
                    selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
                    break;
                case Gravity.RIGHT:
                    selectedOffset = childrenLeft + childrenWidth - width;
                    break;
            }
            sel.offsetLeftAndRight(selectedOffset);
        }

        // Flush any cached views that did not get reused above
        mRecycler.clear();

        invalidate();

        checkSelectionChanged();

        mDataChanged = false;
        mNeedSync = false;
        setNextSelectedPositionInt(mSelectedPosition);
    
private android.view.ViewmakeView(int position, boolean addChild)
Obtain a view, either by pulling an existing view from the recycler or by getting a new one from the adapter. If we are animating, make sure there is enough information in the view's layout parameters to animate from the old to new positions.

param
position Position in the spinner for the view to obtain
param
addChild true to add the child to the spinner, false to obtain and configure only.
return
A view for the given position

        View child;

        if (!mDataChanged) {
            child = mRecycler.get(position);
            if (child != null) {
                // Position the view
                setUpChild(child, addChild);

                return child;
            }
        }

        // Nothing found in the recycler -- ask the adapter for a view
        child = mAdapter.getView(position, null, this);

        // Position the view
        setUpChild(child, addChild);

        return child;
    
intmeasureContentWidth(SpinnerAdapter adapter, android.graphics.drawable.Drawable background)

        if (adapter == null) {
            return 0;
        }

        int width = 0;
        View itemView = null;
        int itemType = 0;
        final int widthMeasureSpec =
            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        final int heightMeasureSpec =
            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

        // Make sure the number of items we'll measure is capped. If it's a huge data set
        // with wildly varying sizes, oh well.
        int start = Math.max(0, getSelectedItemPosition());
        final int end = Math.min(adapter.getCount(), start + MAX_ITEMS_MEASURED);
        final int count = end - start;
        start = Math.max(0, start - (MAX_ITEMS_MEASURED - count));
        for (int i = start; i < end; i++) {
            final int positionType = adapter.getItemViewType(i);
            if (positionType != itemType) {
                itemType = positionType;
                itemView = null;
            }
            itemView = adapter.getView(i, itemView, this);
            if (itemView.getLayoutParams() == null) {
                itemView.setLayoutParams(new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.WRAP_CONTENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT));
            }
            itemView.measure(widthMeasureSpec, heightMeasureSpec);
            width = Math.max(width, itemView.getMeasuredWidth());
        }

        // Add background padding to measured width
        if (background != null) {
            background.getPadding(mTempRect);
            width += mTempRect.left + mTempRect.right;
        }

        return width;
    
public voidonClick(android.content.DialogInterface dialog, int which)

        setSelection(which);
        dialog.dismiss();
    
protected voidonDetachedFromWindow()

        super.onDetachedFromWindow();
        
        if (mPopup != null && mPopup.isShowing()) {
            mPopup.dismiss();
        }
    
public voidonInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)

        super.onInitializeAccessibilityEvent(event);
        event.setClassName(Spinner.class.getName());
    
public voidonInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo info)

        super.onInitializeAccessibilityNodeInfo(info);
        info.setClassName(Spinner.class.getName());

        if (mAdapter != null) {
            info.setCanOpenPopup(true);
        }
    
protected voidonLayout(boolean changed, int l, int t, int r, int b)

see
android.view.View#onLayout(boolean,int,int,int,int) Creates and positions all views

        super.onLayout(changed, l, t, r, b);
        mInLayout = true;
        layout(0, false);
        mInLayout = false;
    
protected voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
            final int measuredWidth = getMeasuredWidth();
            setMeasuredDimension(Math.min(Math.max(measuredWidth,
                    measureContentWidth(getAdapter(), getBackground())),
                    MeasureSpec.getSize(widthMeasureSpec)),
                    getMeasuredHeight());
        }
    
public voidonRestoreInstanceState(android.os.Parcelable state)

        SavedState ss = (SavedState) state;

        super.onRestoreInstanceState(ss.getSuperState());

        if (ss.showDropdown) {
            ViewTreeObserver vto = getViewTreeObserver();
            if (vto != null) {
                final OnGlobalLayoutListener listener = new OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        if (!mPopup.isShowing()) {
                            mPopup.show(getTextDirection(), getTextAlignment());
                        }
                        final ViewTreeObserver vto = getViewTreeObserver();
                        if (vto != null) {
                            vto.removeOnGlobalLayoutListener(this);
                        }
                    }
                };
                vto.addOnGlobalLayoutListener(listener);
            }
        }
    
public android.os.ParcelableonSaveInstanceState()

        final SavedState ss = new SavedState(super.onSaveInstanceState());
        ss.showDropdown = mPopup != null && mPopup.isShowing();
        return ss;
    
public booleanonTouchEvent(android.view.MotionEvent event)

        if (mForwardingListener != null && mForwardingListener.onTouch(this, event)) {
            return true;
        }

        return super.onTouchEvent(event);
    
public booleanperformClick()

        boolean handled = super.performClick();
        
        if (!handled) {
            handled = true;

            if (!mPopup.isShowing()) {
                mPopup.show(getTextDirection(), getTextAlignment());
            }
        }

        return handled;
    
public voidsetAdapter(SpinnerAdapter adapter)
Sets the Adapter used to provide the data which backs this Spinner.

Note that Spinner overrides {@link Adapter#getViewTypeCount()} on the Adapter associated with this view. Calling {@link Adapter#getItemViewType(int) getItemViewType(int)} on the object returned from {@link #getAdapter()} will always return 0. Calling {@link Adapter#getViewTypeCount() getViewTypeCount()} will always return 1. On API {@link Build.VERSION_CODES#LOLLIPOP} and above, attempting to set an adapter with more than one view type will throw an {@link IllegalArgumentException}.

param
adapter the adapter to set
see
AbsSpinner#setAdapter(SpinnerAdapter)
throws
IllegalArgumentException if the adapter has more than one view type

        super.setAdapter(adapter);

        mRecycler.clear();

        final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
        if (targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP
                && adapter != null && adapter.getViewTypeCount() != 1) {
            throw new IllegalArgumentException("Spinner adapter view type count must be 1");
        }

        if (mPopup != null) {
            mPopup.setAdapter(new DropDownAdapter(adapter));
        } else {
            mTempAdapter = new DropDownAdapter(adapter);
        }
    
public voidsetDropDownHorizontalOffset(int pixels)
Set a horizontal offset in pixels for the spinner's popup window of choices. Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.

param
pixels Horizontal offset in pixels
attr
ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset

        mPopup.setHorizontalOffset(pixels);
    
public voidsetDropDownVerticalOffset(int pixels)
Set a vertical offset in pixels for the spinner's popup window of choices. Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.

param
pixels Vertical offset in pixels
attr
ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset

        mPopup.setVerticalOffset(pixels);
    
public voidsetDropDownWidth(int pixels)
Set the width of the spinner's popup window of choices in pixels. This value may also be set to {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} to match the width of the Spinner itself, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} to wrap to the measured size of contained dropdown list items.

Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.

param
pixels Width in pixels, WRAP_CONTENT, or MATCH_PARENT
attr
ref android.R.styleable#Spinner_dropDownWidth

        if (!(mPopup instanceof DropdownPopup)) {
            Log.e(TAG, "Cannot set dropdown width for MODE_DIALOG, ignoring");
            return;
        }
        mDropDownWidth = pixels;
    
public voidsetEnabled(boolean enabled)

        super.setEnabled(enabled);
        if (mDisableChildrenWhenDisabled) {
            final int count = getChildCount();
            for (int i = 0; i < count; i++) {
                getChildAt(i).setEnabled(enabled);
            }
        }
    
public voidsetGravity(int gravity)
Describes how the selected item view is positioned. Currently only the horizontal component is used. The default is determined by the current theme.

param
gravity See {@link android.view.Gravity}
attr
ref android.R.styleable#Spinner_gravity

        if (mGravity != gravity) {
            if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
                gravity |= Gravity.START;
            }
            mGravity = gravity;
            requestLayout();
        }
    
public voidsetOnItemClickListener(OnItemClickListener l)

A spinner does not support item click events. Calling this method will raise an exception.

Instead use {@link AdapterView#setOnItemSelectedListener}.

param
l this listener will be ignored

        throw new RuntimeException("setOnItemClickListener cannot be used with a spinner.");
    
public voidsetOnItemClickListenerInt(OnItemClickListener l)

hide
internal use only

        super.setOnItemClickListener(l);
    
public voidsetPopupBackgroundDrawable(android.graphics.drawable.Drawable background)
Set the background drawable for the spinner's popup window of choices. Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.

param
background Background drawable
attr
ref android.R.styleable#Spinner_popupBackground

        if (!(mPopup instanceof DropdownPopup)) {
            Log.e(TAG, "setPopupBackgroundDrawable: incompatible spinner mode; ignoring...");
            return;
        }
        ((DropdownPopup) mPopup).setBackgroundDrawable(background);
    
public voidsetPopupBackgroundResource(int resId)
Set the background drawable for the spinner's popup window of choices. Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.

param
resId Resource ID of a background drawable
attr
ref android.R.styleable#Spinner_popupBackground

        setPopupBackgroundDrawable(getContext().getDrawable(resId));
    
public voidsetPrompt(java.lang.CharSequence prompt)
Sets the prompt to display when the dialog is shown.

param
prompt the prompt to set

        mPopup.setPromptText(prompt);
    
public voidsetPromptId(int promptId)
Sets the prompt to display when the dialog is shown.

param
promptId the resource ID of the prompt to display when the dialog is shown

        setPrompt(getContext().getText(promptId));
    
private voidsetUpChild(android.view.View child, boolean addChild)
Helper for makeAndAddView to set the position of a view and fill out its layout paramters.

param
child The view to position
param
addChild true if the child should be added to the Spinner during setup


        // Respect layout params that are already in the view. Otherwise
        // make some up...
        ViewGroup.LayoutParams lp = child.getLayoutParams();
        if (lp == null) {
            lp = generateDefaultLayoutParams();
        }

        if (addChild) {
            addViewInLayout(child, 0, lp);
        }

        child.setSelected(hasFocus());
        if (mDisableChildrenWhenDisabled) {
            child.setEnabled(isEnabled());
        }

        // Get measure specs
        int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,
                mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height);
        int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
                mSpinnerPadding.left + mSpinnerPadding.right, lp.width);

        // Measure child
        child.measure(childWidthSpec, childHeightSpec);

        int childLeft;
        int childRight;

        // Position vertically based on gravity setting
        int childTop = mSpinnerPadding.top
                + ((getMeasuredHeight() - mSpinnerPadding.bottom -
                        mSpinnerPadding.top - child.getMeasuredHeight()) / 2);
        int childBottom = childTop + child.getMeasuredHeight();

        int width = child.getMeasuredWidth();
        childLeft = 0;
        childRight = childLeft + width;

        child.layout(childLeft, childTop, childRight, childBottom);