FileDocCategorySizeDatePackage
Gallery.javaAPI DocAndroid 1.5 API44585Wed May 06 22:41:56 BST 2009android.widget

Gallery

public class Gallery extends android.widget.AbsSpinner implements GestureDetector.OnGestureListener
A view that shows items in a center-locked, horizontally scrolling list.

The default values for the Gallery assume you will be using {@link android.R.styleable#Theme_galleryItemBackground} as the background for each View given to the Gallery from the Adapter. If you are not doing this, you may need to adjust some Gallery properties, such as the spacing.

Views given to the Gallery should use {@link Gallery.LayoutParams} as their layout parameters type.

attr
ref android.R.styleable#Gallery_animationDuration
attr
ref android.R.styleable#Gallery_spacing
attr
ref android.R.styleable#Gallery_gravity

Fields Summary
private static final String
TAG
private static final boolean
localLOGV
private static final int
SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT
Duration in milliseconds from the start of a scroll during which we're unsure whether the user is scrolling or flinging.
private int
mSpacing
Horizontal spacing between items.
private int
mAnimationDuration
How long the transition animation should run when a child view changes position, measured in milliseconds.
private float
mUnselectedAlpha
The alpha of items that are not selected.
private int
mLeftMost
Left most edge of a child seen so far during layout.
private int
mRightMost
Right most edge of a child seen so far during layout.
private int
mGravity
private android.view.GestureDetector
mGestureDetector
Helper for detecting touch gestures.
private int
mDownTouchPosition
The position of the item that received the user's down touch.
private android.view.View
mDownTouchView
The view of the item that received the user's down touch.
private FlingRunnable
mFlingRunnable
Executes the delta scrolls from a fling or scroll movement.
private Runnable
mDisableSuppressSelectionChangedRunnable
Sets mSuppressSelectionChanged = false. This is used to set it to false in the future. It will also trigger a selection changed.
private boolean
mShouldStopFling
When fling runnable runs, it resets this to false. Any method along the path until the end of its run() can set this to true to abort any remaining fling. For example, if we've reached either the leftmost or rightmost item, we will set this to true.
private android.view.View
mSelectedChild
The currently selected item's child.
private boolean
mShouldCallbackDuringFling
Whether to continuously callback on the item selected listener during a fling.
private boolean
mShouldCallbackOnUnselectedItemClick
Whether to callback when an item that is not selected is clicked.
private boolean
mSuppressSelectionChanged
If true, do not callback to item selected listener.
private boolean
mReceivedInvokeKeyDown
If true, we have received the "invoke" (center or enter buttons) key down. This is checked before we action on the "invoke" key up, and is subsequently cleared.
private AdapterContextMenuInfo
mContextMenuInfo
private boolean
mIsFirstScroll
If true, this onScroll is the first for this user's drag (remember, a drag sends many onScrolls).
Constructors Summary
public Gallery(android.content.Context context)

    
       
        this(context, null);
    
public Gallery(android.content.Context context, android.util.AttributeSet attrs)

        this(context, attrs, R.attr.galleryStyle);
    
public Gallery(android.content.Context context, android.util.AttributeSet attrs, int defStyle)

        super(context, attrs, defStyle);
        
        mGestureDetector = new GestureDetector(context, this);
        mGestureDetector.setIsLongpressEnabled(true);
        
        TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.Gallery, defStyle, 0);

        int index = a.getInt(com.android.internal.R.styleable.Gallery_gravity, -1);
        if (index >= 0) {
            setGravity(index);
        }

        int animationDuration =
                a.getInt(com.android.internal.R.styleable.Gallery_animationDuration, -1);
        if (animationDuration > 0) {
            setAnimationDuration(animationDuration);
        }

        int spacing =
                a.getDimensionPixelOffset(com.android.internal.R.styleable.Gallery_spacing, 0);
        setSpacing(spacing);

        float unselectedAlpha = a.getFloat(
                com.android.internal.R.styleable.Gallery_unselectedAlpha, 0.5f);
        setUnselectedAlpha(unselectedAlpha);
        
        a.recycle();

        // We draw the selected item last (because otherwise the item to the
        // right overlaps it)
        mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
        
        mGroupFlags |= FLAG_SUPPORT_STATIC_TRANSFORMATIONS;
    
Methods Summary
private intcalculateTop(android.view.View child, android.widget.Gallery$LayoutParams lp, boolean duringLayout)
Figure out vertical placement based on mGravity

param
child Child to place
param
lp LayoutParams for this view (just so we don't keep looking them up)
return
Where the top of the child should be

        int myHeight = duringLayout ? mMeasuredHeight : getHeight();
        int childHeight = duringLayout ? child.getMeasuredHeight() : child.getHeight(); 
        
        int childTop = 0;

        switch (mGravity) {
        case Gravity.TOP:
            childTop = mSpinnerPadding.top;
            break;
        case Gravity.CENTER_VERTICAL:
            int availableSpace = myHeight - mSpinnerPadding.bottom
                    - mSpinnerPadding.top - childHeight;
            childTop = mSpinnerPadding.top + (availableSpace / 2);
            break;
        case Gravity.BOTTOM:
            childTop = myHeight - mSpinnerPadding.bottom - childHeight;
            break;
        }
        return childTop;
    
protected booleancheckLayoutParams(ViewGroup.LayoutParams p)

        return p instanceof LayoutParams;
    
protected intcomputeHorizontalScrollExtent()

        // Only 1 item is considered to be selected
        return 1;
    
protected intcomputeHorizontalScrollOffset()

        // Current scroll position is the same as the selected position
        return mSelectedPosition;
    
protected intcomputeHorizontalScrollRange()

        // Scroll range is the same as the item count
        return mItemCount;
    
private voiddetachOffScreenChildren(boolean toLeft)
Detaches children that are off the screen (i.e.: Gallery bounds).

param
toLeft Whether to detach children to the left of the Gallery, or to the right.

        int numChildren = getChildCount();
        int firstPosition = mFirstPosition;
        int start = 0;
        int count = 0;

        if (toLeft) {
            final int galleryLeft = mPaddingLeft;
            for (int i = 0; i < numChildren; i++) {
                final View child = getChildAt(i);
                if (child.getRight() >= galleryLeft) {
                    break;
                } else {
                    count++;
                    mRecycler.put(firstPosition + i, child);
                }
            }
        } else {
            final int galleryRight = getWidth() - mPaddingRight;
            for (int i = numChildren - 1; i >= 0; i--) {
                final View child = getChildAt(i);
                if (child.getLeft() <= galleryRight) {
                    break;
                } else {
                    start = i;
                    count++;
                    mRecycler.put(firstPosition + i, child);
                }
            }
        }

        detachViewsFromParent(start, count);
        
        if (toLeft) {
            mFirstPosition += count;
        }
    
public booleandispatchKeyEvent(android.view.KeyEvent event)

        // Gallery steals all key events
        return event.dispatch(this);
    
private booleandispatchLongPress(android.view.View view, int position, long id)

        boolean handled = false;
        
        if (mOnItemLongClickListener != null) {
            handled = mOnItemLongClickListener.onItemLongClick(this, mDownTouchView,
                    mDownTouchPosition, id);
        }

        if (!handled) {
            mContextMenuInfo = new AdapterContextMenuInfo(view, position, id);
            handled = super.showContextMenuForChild(this);
        }

        if (handled) {
            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        }
        
        return handled;
    
private voiddispatchPress(android.view.View child)

        
        if (child != null) {
            child.setPressed(true);
        }
        
        setPressed(true);
    
protected voiddispatchSetPressed(boolean pressed)

        
        // Show the pressed state on the selected child
        if (mSelectedChild != null) {
            mSelectedChild.setPressed(pressed);
        }
    
public voiddispatchSetSelected(boolean selected)

        /*
         * We don't want to pass the selected state given from its parent to its
         * children since this widget itself has a selected state to give to its
         * children.
         */
    
private voiddispatchUnpress()

        
        for (int i = getChildCount() - 1; i >= 0; i--) {
            getChildAt(i).setPressed(false);
        }
        
        setPressed(false);
    
private voidfillToGalleryLeft()

        int itemSpacing = mSpacing;
        int galleryLeft = mPaddingLeft;
        
        // Set state for initial iteration
        View prevIterationView = getChildAt(0);
        int curPosition;
        int curRightEdge;
        
        if (prevIterationView != null) {
            curPosition = mFirstPosition - 1;
            curRightEdge = prevIterationView.getLeft() - itemSpacing;
        } else {
            // No children available!
            curPosition = 0; 
            curRightEdge = mRight - mLeft - mPaddingRight;
            mShouldStopFling = true;
        }
                
        while (curRightEdge > galleryLeft && curPosition >= 0) {
            prevIterationView = makeAndAddView(curPosition, curPosition - mSelectedPosition,
                    curRightEdge, false);

            // Remember some state
            mFirstPosition = curPosition;
            
            // Set state for next iteration
            curRightEdge = prevIterationView.getLeft() - itemSpacing;
            curPosition--;
        }
    
private voidfillToGalleryRight()

        int itemSpacing = mSpacing;
        int galleryRight = mRight - mLeft - mPaddingRight;
        int numChildren = getChildCount();
        int numItems = mItemCount;
        
        // Set state for initial iteration
        View prevIterationView = getChildAt(numChildren - 1);
        int curPosition;
        int curLeftEdge;
        
        if (prevIterationView != null) {
            curPosition = mFirstPosition + numChildren;
            curLeftEdge = prevIterationView.getRight() + itemSpacing;
        } else {
            mFirstPosition = curPosition = mItemCount - 1;
            curLeftEdge = mPaddingLeft;
            mShouldStopFling = true;
        }
                
        while (curLeftEdge < galleryRight && curPosition < numItems) {
            prevIterationView = makeAndAddView(curPosition, curPosition - mSelectedPosition,
                    curLeftEdge, true);

            // Set state for next iteration
            curLeftEdge = prevIterationView.getRight() + itemSpacing;
            curPosition++;
        }
    
protected ViewGroup.LayoutParamsgenerateDefaultLayoutParams()

        /*
         * Gallery expects Gallery.LayoutParams.
         */
        return new Gallery.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
    
protected ViewGroup.LayoutParamsgenerateLayoutParams(ViewGroup.LayoutParams p)

        return new LayoutParams(p);
    
public ViewGroup.LayoutParamsgenerateLayoutParams(android.util.AttributeSet attrs)

        return new LayoutParams(getContext(), attrs);
    
private intgetCenterOfGallery()

return
The center of this Gallery.

        return (getWidth() - mPaddingLeft - mPaddingRight) / 2 + mPaddingLeft;
    
private static intgetCenterOfView(android.view.View view)

return
The center of the given view.

        return view.getLeft() + view.getWidth() / 2;
    
protected intgetChildDrawingOrder(int childCount, int i)

        int selectedIndex = mSelectedPosition - mFirstPosition;
        
        // Just to be safe
        if (selectedIndex < 0) return i;
        
        if (i == childCount - 1) {
            // Draw the selected child last
            return selectedIndex;
        } else if (i >= selectedIndex) {
            // Move the children to the right of the selected child earlier one
            return i + 1;
        } else {
            // Keep the children to the left of the selected child the same
            return i;
        }
    
intgetChildHeight(android.view.View child)

        return child.getMeasuredHeight();
    
protected booleangetChildStaticTransformation(android.view.View child, android.view.animation.Transformation t)

        
        t.clear();
        t.setAlpha(child == mSelectedChild ? 1.0f : mUnselectedAlpha);
        
        return true;
    
protected android.view.ContextMenu.ContextMenuInfogetContextMenuInfo()

        return mContextMenuInfo;
    
intgetLimitedMotionScrollAmount(boolean motionToLeft, int deltaX)

        int extremeItemPosition = motionToLeft ? mItemCount - 1 : 0;
        View extremeChild = getChildAt(extremeItemPosition - mFirstPosition);
        
        if (extremeChild == null) {
            return deltaX;
        }
        
        int extremeChildCenter = getCenterOfView(extremeChild);
        int galleryCenter = getCenterOfGallery();
        
        if (motionToLeft) {
            if (extremeChildCenter <= galleryCenter) {
                
                // The extreme child is past his boundary point!
                return 0;
            }
        } else {
            if (extremeChildCenter >= galleryCenter) {

                // The extreme child is past his boundary point!
                return 0;
            }
        }
        
        int centerDifference = galleryCenter - extremeChildCenter;

        return motionToLeft
                ? Math.max(centerDifference, deltaX)
                : Math.min(centerDifference, deltaX); 
    
voidlayout(int delta, boolean animate)
Creates and positions all views for this Gallery.

We layout rarely, most of the time {@link #trackMotionScroll(int)} takes care of repositioning, adding, and removing children.

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


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

        if (mDataChanged) {
            handleDataChanged();
        }

        // Handle an empty gallery by removing all views.
        if (mItemCount == 0) {
            resetList();
            return;
        }

        // Update to the new selected position.
        if (mNextSelectedPosition >= 0) {
            setSelectedPositionInt(mNextSelectedPosition);
        }

        // All views go in recycler while we are in layout
        recycleAllViews();

        // Clear out old views
        //removeAllViewsInLayout();
        detachAllViewsFromParent();

        /*
         * These will be used to give initial positions to views entering the
         * gallery as we scroll
         */
        mRightMost = 0;
        mLeftMost = 0;

        // Make selected view and center it
        
        /*
         * mFirstPosition will be decreased as we add views to the left later
         * on. The 0 for x will be offset in a couple lines down.
         */  
        mFirstPosition = mSelectedPosition;
        View sel = makeAndAddView(mSelectedPosition, 0, 0, true);
        
        // Put the selected child in the center
        Gallery.LayoutParams lp = (Gallery.LayoutParams) sel.getLayoutParams();
        int selectedOffset = childrenLeft + (childrenWidth / 2) - (sel.getWidth() / 2);
        sel.offsetLeftAndRight(selectedOffset);

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

        invalidate();
        checkSelectionChanged();

        mDataChanged = false;
        mNeedSync = false;
        setNextSelectedPositionInt(mSelectedPosition);
        
        updateSelectedItemMetadata();
    
private android.view.ViewmakeAndAddView(int position, int offset, int x, boolean fromLeft)
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 gallery for the view to obtain
param
offset Offset from the selected position
param
x X-coordintate indicating where this view should be placed. This will either be the left or right edge of the view, depending on the fromLeft paramter
param
fromLeft Are we posiitoning views based on the left edge? (i.e., building from left to right)?
return
A view that has been added to the gallery


        View child;

        if (!mDataChanged) {
            child = mRecycler.get(position);
            if (child != null) {
                // Can reuse an existing view
                Gallery.LayoutParams lp = (Gallery.LayoutParams) 
                    child.getLayoutParams();

                int childLeft = child.getLeft();
                
                // Remember left and right edges of where views have been placed
                mRightMost = Math.max(mRightMost, childLeft 
                        + child.getMeasuredWidth());
                mLeftMost = Math.min(mLeftMost, childLeft);

                // Position the view
                setUpChild(child, offset, x, fromLeft);

                return child;
            }
        }

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

        // Position the view
        setUpChild(child, offset, x, fromLeft);

        return child;
    
booleanmoveNext()

        if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
            scrollToChild(mSelectedPosition - mFirstPosition + 1);
            return true;
        } else {
            return false;
        }
    
booleanmovePrevious()

        if (mItemCount > 0 && mSelectedPosition > 0) {
            scrollToChild(mSelectedPosition - mFirstPosition - 1);
            return true;
        } else {
            return false;
        }
    
private voidoffsetChildrenLeftAndRight(int offset)
Offset the horizontal location of all children of this view by the specified number of pixels.

param
offset the number of pixels to offset

        for (int i = getChildCount() - 1; i >= 0; i--) {
            getChildAt(i).offsetLeftAndRight(offset);
        }
    
voidonCancel()
Called when a touch event's action is MotionEvent.ACTION_CANCEL.

        onUp();
    
public booleanonDown(android.view.MotionEvent e)
{@inheritDoc}


        // Kill any existing fling/scroll
        mFlingRunnable.stop(false);

        // Get the item's view that was touched
        mDownTouchPosition = pointToPosition((int) e.getX(), (int) e.getY());
        
        if (mDownTouchPosition >= 0) {
            mDownTouchView = getChildAt(mDownTouchPosition - mFirstPosition);
            mDownTouchView.setPressed(true);
        }
        
        // Reset the multiple-scroll tracking state
        mIsFirstScroll = true;
        
        // Must return true to get matching events for this down event.
        return true;
    
private voidonFinishedMovement()

        if (mSuppressSelectionChanged) {
            mSuppressSelectionChanged = false;
            
            // We haven't been callbacking during the fling, so do it now
            super.selectionChanged();
        }
    
public booleanonFling(android.view.MotionEvent e1, android.view.MotionEvent e2, float velocityX, float velocityY)
{@inheritDoc}

        
        if (!mShouldCallbackDuringFling) {
            // We want to suppress selection changes
            
            // Remove any future code to set mSuppressSelectionChanged = false
            removeCallbacks(mDisableSuppressSelectionChangedRunnable);

            // This will get reset once we scroll into slots
            if (!mSuppressSelectionChanged) mSuppressSelectionChanged = true;
        }
        
        // Fling the gallery!
        mFlingRunnable.startUsingVelocity((int) -velocityX);
        
        return true;
    
protected voidonFocusChanged(boolean gainFocus, int direction, android.graphics.Rect previouslyFocusedRect)

        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
        
        /*
         * The gallery shows focus by focusing the selected item. So, give
         * focus to our selected item instead. We steal keys from our
         * selected item elsewhere.
         */
        if (gainFocus && mSelectedChild != null) {
            mSelectedChild.requestFocus(direction);
        }

    
public booleanonKeyDown(int keyCode, android.view.KeyEvent event)
Handles left, right, and clicking

see
android.view.View#onKeyDown

        switch (keyCode) {
            
        case KeyEvent.KEYCODE_DPAD_LEFT:
            if (movePrevious()) {
                playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
            }
            return true;

        case KeyEvent.KEYCODE_DPAD_RIGHT:
            if (moveNext()) {
                playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
            }
            return true;

        case KeyEvent.KEYCODE_DPAD_CENTER:
        case KeyEvent.KEYCODE_ENTER:
            mReceivedInvokeKeyDown = true;
            // fallthrough to default handling
        }
        
        return super.onKeyDown(keyCode, event);
    
public booleanonKeyUp(int keyCode, android.view.KeyEvent event)

        switch (keyCode) {
        case KeyEvent.KEYCODE_DPAD_CENTER:
        case KeyEvent.KEYCODE_ENTER: {
            
            if (mReceivedInvokeKeyDown) {
                if (mItemCount > 0) {
    
                    dispatchPress(mSelectedChild);
                    postDelayed(new Runnable() {
                        public void run() {
                            dispatchUnpress();
                        }
                    }, ViewConfiguration.getPressedStateDuration());
    
                    int selectedIndex = mSelectedPosition - mFirstPosition;
                    performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter
                            .getItemId(mSelectedPosition));
                }
            }
            
            // Clear the flag
            mReceivedInvokeKeyDown = false;
            
            return true;
        }
        }

        return super.onKeyUp(keyCode, event);
    
protected voidonLayout(boolean changed, int l, int t, int r, int b)

        super.onLayout(changed, l, t, r, b);
        
        /*
         * Remember that we are in layout to prevent more layout request from
         * being generated.
         */
        mInLayout = true;
        layout(0, false);
        mInLayout = false;
    
public voidonLongPress(android.view.MotionEvent e)
{@inheritDoc}

        
        if (mDownTouchPosition < 0) {
            return;
        }
        
        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        long id = getItemIdAtPosition(mDownTouchPosition);
        dispatchLongPress(mDownTouchView, mDownTouchPosition, id);
    
public booleanonScroll(android.view.MotionEvent e1, android.view.MotionEvent e2, float distanceX, float distanceY)
{@inheritDoc}


        if (localLOGV) Log.v(TAG, String.valueOf(e2.getX() - e1.getX()));
        
        /*
         * Now's a good time to tell our parent to stop intercepting our events!
         * The user has moved more than the slop amount, since GestureDetector
         * ensures this before calling this method. Also, if a parent is more
         * interested in this touch's events than we are, it would have
         * intercepted them by now (for example, we can assume when a Gallery is
         * in the ListView, a vertical scroll would not end up in this method
         * since a ListView would have intercepted it by now).
         */
        mParent.requestDisallowInterceptTouchEvent(true);
        
        // As the user scrolls, we want to callback selection changes so related-
        // info on the screen is up-to-date with the gallery's selection
        if (!mShouldCallbackDuringFling) {
            if (mIsFirstScroll) {
                /*
                 * We're not notifying the client of selection changes during
                 * the fling, and this scroll could possibly be a fling. Don't
                 * do selection changes until we're sure it is not a fling.
                 */
                if (!mSuppressSelectionChanged) mSuppressSelectionChanged = true;
                postDelayed(mDisableSuppressSelectionChangedRunnable, SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT);
            }
        } else {
            if (mSuppressSelectionChanged) mSuppressSelectionChanged = false;
        }
        
        // Track the motion
        trackMotionScroll(-1 * (int) distanceX);
       
        mIsFirstScroll = false;
        return true;
    
public voidonShowPress(android.view.MotionEvent e)
{@inheritDoc}

    
public booleanonSingleTapUp(android.view.MotionEvent e)
{@inheritDoc}


        if (mDownTouchPosition >= 0) {
            
            // An item tap should make it selected, so scroll to this child.
            scrollToChild(mDownTouchPosition - mFirstPosition);

            // Also pass the click so the client knows, if it wants to.
            if (mShouldCallbackOnUnselectedItemClick || mDownTouchPosition == mSelectedPosition) {
                performItemClick(mDownTouchView, mDownTouchPosition, mAdapter
                        .getItemId(mDownTouchPosition));
            }
            
            return true;
        }
        
        return false;
    
public booleanonTouchEvent(android.view.MotionEvent event)


        // Give everything to the gesture detector
        boolean retValue = mGestureDetector.onTouchEvent(event);

        int action = event.getAction();
        if (action == MotionEvent.ACTION_UP) {
            // Helper method for lifted finger
            onUp();
        } else if (action == MotionEvent.ACTION_CANCEL) {
            onCancel();
        }
        
        return retValue;
    
voidonUp()
Called when a touch event's action is MotionEvent.ACTION_UP.

        
        if (mFlingRunnable.mScroller.isFinished()) {
            scrollIntoSlots();
        }
        
        dispatchUnpress();
    
private voidscrollIntoSlots()
Scrolls the items so that the selected item is in its 'slot' (its center is the gallery's center).

        
        if (getChildCount() == 0 || mSelectedChild == null) return;
        
        int selectedCenter = getCenterOfView(mSelectedChild);
        int targetCenter = getCenterOfGallery();
        
        int scrollAmount = targetCenter - selectedCenter;
        if (scrollAmount != 0) {
            mFlingRunnable.startUsingDistance(scrollAmount);
        } else {
            onFinishedMovement();
        }
    
private booleanscrollToChild(int childPosition)

        View child = getChildAt(childPosition);
        
        if (child != null) {
            int distance = getCenterOfGallery() - getCenterOfView(child);
            mFlingRunnable.startUsingDistance(distance);
            return true;
        }
        
        return false;
    
voidselectionChanged()

        if (!mSuppressSelectionChanged) {
            super.selectionChanged();
        }
    
public voidsetAnimationDuration(int animationDurationMillis)
Sets how long the transition animation should run when a child view changes position. Only relevant if animation is turned on.

param
animationDurationMillis The duration of the transition, in milliseconds.
attr
ref android.R.styleable#Gallery_animationDuration

        mAnimationDuration = animationDurationMillis;
    
public voidsetCallbackDuringFling(boolean shouldCallback)
Whether or not to callback on any {@link #getOnItemSelectedListener()} while the items are being flinged. If false, only the final selected item will cause the callback. If true, all items between the first and the final will cause callbacks.

param
shouldCallback Whether or not to callback on the listener while the items are being flinged.

        mShouldCallbackDuringFling = shouldCallback;
    
public voidsetCallbackOnUnselectedItemClick(boolean shouldCallback)
Whether or not to callback when an item that is not selected is clicked. If false, the item will become selected (and re-centered). If true, the {@link #getOnItemClickListener()} will get the callback.

param
shouldCallback Whether or not to callback on the listener when a item that is not selected is clicked.
hide

        mShouldCallbackOnUnselectedItemClick = shouldCallback;
    
public voidsetGravity(int gravity)
Describes how the child views are aligned.

param
gravity
attr
ref android.R.styleable#Gallery_gravity

        if (mGravity != gravity) {
            mGravity = gravity;
            requestLayout();
        }
    
voidsetSelectedPositionInt(int position)

        super.setSelectedPositionInt(position);

        // Updates any metadata we keep about the selected item.
        updateSelectedItemMetadata();
    
private voidsetSelectionToCenterChild()
Looks for the child that is closest to the center and sets it as the selected child.

        
        View selView = mSelectedChild;
        if (mSelectedChild == null) return;
        
        int galleryCenter = getCenterOfGallery();
        
        if (selView != null) {

            // Common case where the current selected position is correct
            if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) {
                return;
            }
        }
        
        // TODO better search
        int closestEdgeDistance = Integer.MAX_VALUE;
        int newSelectedChildIndex = 0;
        for (int i = getChildCount() - 1; i >= 0; i--) {
            
            View child = getChildAt(i);
            
            if (child.getLeft() <= galleryCenter && child.getRight() >=  galleryCenter) {
                // This child is in the center
                newSelectedChildIndex = i;
                break;
            }
            
            int childClosestEdgeDistance = Math.min(Math.abs(child.getLeft() - galleryCenter),
                    Math.abs(child.getRight() - galleryCenter));
            if (childClosestEdgeDistance < closestEdgeDistance) {
                closestEdgeDistance = childClosestEdgeDistance;
                newSelectedChildIndex = i;
            }
        }
        
        int newPos = mFirstPosition + newSelectedChildIndex;
        
        if (newPos != mSelectedPosition) {
            setSelectedPositionInt(newPos);
            setNextSelectedPositionInt(newPos);
            checkSelectionChanged();
        }
    
public voidsetSpacing(int spacing)
Sets the spacing between items in a Gallery

param
spacing The spacing in pixels between items in the Gallery
attr
ref android.R.styleable#Gallery_spacing

        mSpacing = spacing;
    
public voidsetUnselectedAlpha(float unselectedAlpha)
Sets the alpha of items that are not selected in the Gallery.

param
unselectedAlpha the alpha for the items that are not selected.
attr
ref android.R.styleable#Gallery_unselectedAlpha

        mUnselectedAlpha = unselectedAlpha;
    
private voidsetUpChild(android.view.View child, int offset, int x, boolean fromLeft)
Helper for makeAndAddView to set the position of a view and fill out its layout paramters.

param
child The view to position
param
offset Offset from the selected position
param
x X-coordintate indicating where this view should be placed. This will either be the left or right edge of the view, depending on the fromLeft paramter
param
fromLeft Are we posiitoning views based on the left edge? (i.e., building from left to right)?


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

        addViewInLayout(child, fromLeft ? -1 : 0, lp);

        child.setSelected(offset == 0);

        // 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 = calculateTop(child, lp, true);
        int childBottom = childTop + child.getMeasuredHeight();

        int width = child.getMeasuredWidth();
        if (fromLeft) {
            childLeft = x;
            childRight = childLeft + width;
        } else {
            childLeft = x - width;
            childRight = x;
        }

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

        
        if (isPressed() && mSelectedPosition >= 0) {
            int index = mSelectedPosition - mFirstPosition;
            View v = getChildAt(index);
            return dispatchLongPress(v, mSelectedPosition, mSelectedRowId);
        }        
        
        return false;
    
public booleanshowContextMenuForChild(android.view.View originalView)


        final int longPressPosition = getPositionForView(originalView);
        if (longPressPosition < 0) {
            return false;
        }
        
        final long longPressId = mAdapter.getItemId(longPressPosition);
        return dispatchLongPress(originalView, longPressPosition, longPressId);
    
voidtrackMotionScroll(int deltaX)
Tracks a motion scroll. In reality, this is used to do just about any movement to items (touch scroll, arrow-key scroll, set an item as selected).

param
deltaX Change in X from the previous event.


        if (getChildCount() == 0) {
            return;
        }
        
        boolean toLeft = deltaX < 0; 
        
        int limitedDeltaX = getLimitedMotionScrollAmount(toLeft, deltaX);
        if (limitedDeltaX != deltaX) {
            // The above call returned a limited amount, so stop any scrolls/flings
            mFlingRunnable.endFling(false);
            onFinishedMovement();
        }
        
        offsetChildrenLeftAndRight(limitedDeltaX);
        
        detachOffScreenChildren(toLeft);
        
        if (toLeft) {
            // If moved left, there will be empty space on the right
            fillToGalleryRight();
        } else {
            // Similarly, empty space on the left
            fillToGalleryLeft();
        }
        
        // Clear unused views
        mRecycler.clear();
        
        setSelectionToCenterChild();
        
        invalidate();
    
private voidupdateSelectedItemMetadata()

        
        View oldSelectedChild = mSelectedChild;

        View child = mSelectedChild = getChildAt(mSelectedPosition - mFirstPosition);
        if (child == null) {
            return;
        }

        child.setSelected(true);
        child.setFocusable(true);

        if (hasFocus()) {
            child.requestFocus();
        }

        // We unfocus the old child down here so the above hasFocus check
        // returns true
        if (oldSelectedChild != null) {

            // Make sure its drawable state doesn't contain 'selected'
            oldSelectedChild.setSelected(false);
            
            // Make sure it is not focusable anymore, since otherwise arrow keys
            // can make this one be focused
            oldSelectedChild.setFocusable(false);
        }