FileDocCategorySizeDatePackage
SpinnerCompat.javaAPI DocAndroid 5.1 API37674Thu Mar 12 22:22:56 GMT 2015android.support.v7.internal.widget

SpinnerCompat

public class SpinnerCompat extends AbsSpinnerCompat implements 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 android.widget.Adapter} associated with this view.

See the Spinner tutorial.

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 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
private final TintManager
mTintManager
Constructors Summary
SpinnerCompat(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);
    
SpinnerCompat(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, R.attr.spinnerStyle, mode);
    
SpinnerCompat(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, R.attr.spinnerStyle);
    
SpinnerCompat(android.content.Context context, android.util.AttributeSet attrs, int defStyle)
Construct a new spinner with the given context's theme, the supplied attribute set, and default style.

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
defStyle The default style to apply to this view. If 0, no style will be applied (beyond what is included in the theme). This may either be an attribute resource, whose value will be retrieved from the current theme, or an explicit style resource.

        this(context, attrs, defStyle, MODE_THEME);
    
SpinnerCompat(android.content.Context context, android.util.AttributeSet attrs, int defStyle, 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
defStyle The default style to apply to this view. If 0, no style will be applied (beyond what is included in the theme). This may either be an attribute resource, whose value will be retrieved from the current theme, or an explicit style resource.
param
mode Constant describing how the user will select choices from the spinner.
see
#MODE_DIALOG
see
#MODE_DROPDOWN

        super(context, attrs, defStyle);

        TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
                R.styleable.Spinner, defStyle, 0);

        // Need to reset this for tinting purposes
        setBackgroundDrawable(a.getDrawable(R.styleable.Spinner_android_background));

        if (mode == MODE_THEME) {
            mode = a.getInt(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, defStyle);

                mDropDownWidth = a.getLayoutDimension(R.styleable.Spinner_android_dropDownWidth,
                        ViewGroup.LayoutParams.WRAP_CONTENT);

                popup.setBackgroundDrawable(
                        a.getDrawable(R.styleable.Spinner_android_popupBackground));

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

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

        mGravity = a.getInt(R.styleable.Spinner_android_gravity, Gravity.CENTER);

        mPopup.setPromptText(a.getString(R.styleable.Spinner_prompt));

        mDisableChildrenWhenDisabled = a.getBoolean(
                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;
        }

        // Keep the TintManager in case we need it later
        mTintManager = a.getTintManager();
    
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

        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

        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

        return mDropDownWidth;
    
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

        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 = getRight() - getLeft() - 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 = ViewCompat.getLayoutDirection(this);
            final int absoluteGravity = GravityCompat.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(android.widget.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();
        }
    
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 ViewTreeObserver.OnGlobalLayoutListener listener
                        = new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        if (!mPopup.isShowing()) {
                            mPopup.show();
                        }
                        final ViewTreeObserver vto = getViewTreeObserver();
                        if (vto != null) {
                            vto.removeGlobalOnLayoutListener(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();
            }
        }

        return handled;
    
public voidsetAdapter(android.widget.SpinnerAdapter adapter)

        super.setAdapter(adapter);

        mRecycler.clear();

        final int targetSdkVersion = getContext().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

        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

        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

        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}

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

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

param
l this listener will be ignored

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

        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

        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

        setPopupBackgroundDrawable(mTintManager.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);