From 45e812012eb67ba341671a79d6b832f8294b2e24 Mon Sep 17 00:00:00 2001
From: BABACHAN
ViewPager is most often used in conjunction with {@link android.app.Fragment}, + *
VerticalViewPager is most often used in conjunction with {@link android.app.Fragment}, * which is a convenient way to supply and manage the lifecycle of each page. - * There are standard adapters implemented for using fragments with the ViewPager, + * There are standard adapters implemented for using fragments with the VerticalViewPager, * which cover the most common use cases. These are - * {@link android.support.v4.app.FragmentPagerAdapter}, - * {@link android.support.v4.app.FragmentStatePagerAdapter}, - * {@link android.support.v13.app.FragmentPagerAdapter}, and - * {@link android.support.v13.app.FragmentStatePagerAdapter}; each of these + * {@link android.support.v4.app.FragmentPagerAdapter} and + * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these * classes have simple code showing how to build a full user interface * with them. * - *
Here is a more complicated example of ViewPager, using it in conjuction + *
Here is a more complicated example of VerticalViewPager, using it in conjuction * with {@link android.app.ActionBar} tabs. You can find other examples of using - * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. + * VerticalViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. * * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java * complete} @@ -107,15 +106,22 @@ public class VerticalViewPager extends ViewGroup { private static final int DEFAULT_GUTTER_SIZE = 16; // dips + private static final int MIN_FLING_VELOCITY = 400; // dips + private static final int[] LAYOUT_ATTRS = new int[] { android.R.attr.layout_gravity }; + /** + * Used to track what the expected number of items in the adapter should be. + * If the app changes this when we don't expect it, we'll throw a big obnoxious exception. + */ + private int mExpectedAdapterCount; + static class ItemInfo { Object object; int position; boolean scrolling; - float widthFactor; float heightFactor; float offset; } @@ -159,6 +165,8 @@ public float getInterpolation(float t) { private float mLastOffset = Float.MAX_VALUE; private int mChildWidthMeasureSpec; + private int mChildHeightMeasureSpec; + private boolean mInLayout; private boolean mScrollingCacheEnabled; @@ -171,13 +179,13 @@ public float getInterpolation(float t) { private int mDefaultGutterSize; private int mGutterSize; private int mTouchSlop; - private float mInitialMotionX; - private float mInitialMotionY; /** * Position of the last motion event. */ private float mLastMotionX; private float mLastMotionY; + private float mInitialMotionX; + private float mInitialMotionY; /** * ID of the active pointer. This is used to retain consistency during * drags/flings if multiple pointers are used. @@ -197,8 +205,6 @@ public float getInterpolation(float t) { private int mMaximumVelocity; private int mFlingDistance; private int mCloseEnough; - private int mSeenPositionMin; - private int mSeenPositionMax; // If the pager is at least this close to its final position, complete the scroll // on touch down and let the user interact with the content inside instead of @@ -318,7 +324,7 @@ public void onPageScrollStateChanged(int state) { * to the page views using animation properties. * *
As property animation is only supported as of Android 3.0 and forward, - * setting a PageTransformer on a ViewPager on earlier platform versions will + * setting a PageTransformer on a VerticalViewPager on earlier platform versions will * be ignored.
*/ public interface PageTransformer { @@ -348,29 +354,29 @@ interface Decor {} public VerticalViewPager(Context context) { super(context); - initViewPager(); + initVerticalViewPager(); } public VerticalViewPager(Context context, AttributeSet attrs) { super(context, attrs); - initViewPager(); + initVerticalViewPager(); } - void initViewPager() { + void initVerticalViewPager() { setWillNotDraw(false); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setFocusable(true); final Context context = getContext(); mScroller = new Scroller(context, sInterpolator); final ViewConfiguration configuration = ViewConfiguration.get(context); + final float density = context.getResources().getDisplayMetrics().density; + mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); - mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); + mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); - mTopEdge = new EdgeEffectCompat(context); mBottomEdge = new EdgeEffectCompat(context); - final float density = context.getResources().getDisplayMetrics().density; mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); mCloseEnough = (int) (CLOSE_ENOUGH * density); mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); @@ -396,9 +402,6 @@ private void setScrollState(int newState) { } mScrollState = newState; - if (newState == SCROLL_STATE_DRAGGING) { - mSeenPositionMin = mSeenPositionMax = -1; - } if (mPageTransformer != null) { // PageTransformers can do complex things that benefit from hardware layers. enableLayers(newState != SCROLL_STATE_IDLE); @@ -430,22 +433,26 @@ public void setAdapter(PagerAdapter adapter) { final PagerAdapter oldAdapter = mAdapter; mAdapter = adapter; + mExpectedAdapterCount = 0; if (mAdapter != null) { if (mObserver == null) { mObserver = new PagerObserver(); } mAdapter.registerDataSetObserver(mObserver); - mPopulatePending = false; + final boolean wasFirstLayout = mFirstLayout; mFirstLayout = true; + mExpectedAdapterCount = mAdapter.getCount(); if (mRestoredCurItem >= 0) { mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); setCurrentItemInternal(mRestoredCurItem, false, true); mRestoredCurItem = -1; mRestoredAdapterState = null; mRestoredClassLoader = null; - } else { + } else if (!wasFirstLayout) { populate(); + } else { + requestLayout(); } } @@ -478,8 +485,12 @@ void setOnAdapterChangeListener(OnAdapterChangeListener listener) { mAdapterChangeListener = listener; } + private int getClientHeight() { + return getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); + } + /** - * Set the currently selected page. If the ViewPager has already been through its first + * Set the currently selected page. If the VerticalViewPager has already been through its first * layout with its current adapter there will be a smooth animated transition between * the current item and the specified item. * @@ -534,8 +545,22 @@ void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int } } final boolean dispatchSelected = mCurItem != item; - populate(item); - scrollToItem(item, smoothScroll, velocity, dispatchSelected); + + if (mFirstLayout) { + // We don't have any idea how big we are yet and shouldn't have any pages either. + // Just set things up and let the pending layout handle things. + mCurItem = item; + if (dispatchSelected && mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(item); + } + if (dispatchSelected && mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageSelected(item); + } + requestLayout(); + } else { + populate(item); + scrollToItem(item, smoothScroll, velocity, dispatchSelected); + } } private void scrollToItem(int item, boolean smoothScroll, int velocity, @@ -543,12 +568,12 @@ private void scrollToItem(int item, boolean smoothScroll, int velocity, final ItemInfo curInfo = infoForPosition(item); int destY = 0; if (curInfo != null) { - final int height = getHeight(); + final int height = getClientHeight(); destY = (int) (height * Math.max(mFirstOffset, Math.min(curInfo.offset, mLastOffset))); } if (smoothScroll) { - smoothScrollTo(0, destY, velocity); + smoothScrollTo(0, destY, velocity); if (dispatchSelected && mOnPageChangeListener != null) { mOnPageChangeListener.onPageSelected(item); @@ -565,6 +590,7 @@ private void scrollToItem(int item, boolean smoothScroll, int velocity, } completeScroll(false); scrollTo(0, destY); + pageScrolled(destY); } } @@ -579,17 +605,17 @@ public void setOnPageChangeListener(OnPageChangeListener listener) { } /** - * Set a {@link PageTransformer} that will be called for each attached page whenever - * the scroll position is changed. This allows the application to apply custom property - * transformations to each page, overriding the default sliding look and feel. - * - *Note: Prior to Android 3.0 the property animation APIs did not exist. - * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.
- * - * @param reverseDrawingOrder true if the supplied PageTransformer requires page views - * to be drawn from last to first instead of first to last. - * @param transformer PageTransformer that will modify each page's animation properties - */ + * Set a {@link PageTransformer} that will be called for each attached page whenever + * the scroll position is changed. This allows the application to apply custom property + * transformations to each page, overriding the default sliding look and feel. + * + *Note: Prior to Android 3.0 the property animation APIs did not exist. + * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.
+ * + * @param reverseDrawingOrder true if the supplied PageTransformer requires page views + * to be drawn from last to first instead of first to last. + * @param transformer PageTransformer that will modify each page's animation properties + */ public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) { if (Build.VERSION.SDK_INT >= 11) { final boolean hasTransformer = transformer != null; @@ -606,18 +632,20 @@ public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer tran } void setChildrenDrawingOrderEnabledCompat(boolean enable) { - if (mSetChildrenDrawingOrderEnabled == null) { - try { - mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod( - "setChildrenDrawingOrderEnabled", new Class[] { Boolean.TYPE }); - } catch (NoSuchMethodException e) { - Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e); - } - } - try { - mSetChildrenDrawingOrderEnabled.invoke(this, enable); - } catch (Exception e) { - Log.e(TAG, "Error changing children drawing order", e); + if (Build.VERSION.SDK_INT >= 7) { + if (mSetChildrenDrawingOrderEnabled == null) { + try { + mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod( + "setChildrenDrawingOrderEnabled", new Class[] { Boolean.TYPE }); + } catch (NoSuchMethodException e) { + Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e); + } + } + try { + mSetChildrenDrawingOrderEnabled.invoke(this, enable); + } catch (Exception e) { + Log.e(TAG, "Error changing children drawing order", e); + } } } @@ -771,7 +799,6 @@ void smoothScrollTo(int x, int y) { */ void smoothScrollTo(int x, int y, int velocity) { -// void smoothScrollTo(int y, int x, int velocity) { if (getChildCount() == 0) { // Nothing to do. setScrollingCacheEnabled(false); @@ -794,7 +821,7 @@ void smoothScrollTo(int x, int y, int velocity) { setScrollingCacheEnabled(true); setScrollState(SCROLL_STATE_SETTLING); - final int height = getHeight(); + final int height = getClientHeight(); final int halfHeight = height / 2; final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / height); final float distance = halfHeight + halfHeight * distanceInfluenceForSnapDuration(distanceRatio); @@ -805,7 +832,7 @@ void smoothScrollTo(int x, int y, int velocity) { duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); } else { final float pageHeight = height * mAdapter.getPageHeight(mCurItem); - final float pageDelta = (float) Math.abs(dx) / (pageHeight + mPageMargin); + final float pageDelta = (float) Math.abs(dy) / (pageHeight + mPageMargin); duration = (int) ((pageDelta + 1) * 100); } duration = Math.min(duration, MAX_SETTLE_DURATION); @@ -818,7 +845,6 @@ ItemInfo addNewItem(int position, int index) { ItemInfo ii = new ItemInfo(); ii.position = position; ii.object = mAdapter.instantiateItem(this, position); - ii.widthFactor = mAdapter.getPageWidth(position); ii.heightFactor = mAdapter.getPageHeight(position); if (index < 0 || index >= mItems.size()) { @@ -832,8 +858,10 @@ ItemInfo addNewItem(int position, int index) { void dataSetChanged() { // This method only gets called if our observer is attached, so mAdapter is non-null. + final int adapterCount = mAdapter.getCount(); + mExpectedAdapterCount = adapterCount; boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && - mItems.size() < mAdapter.getCount(); + mItems.size() < adapterCount; int newCurrItem = mCurItem; boolean isUpdating = false; @@ -859,7 +887,7 @@ void dataSetChanged() { if (mCurItem == ii.position) { // Keep the current item in the valid range - newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1)); + newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1)); needPopulate = true; } continue; @@ -889,7 +917,6 @@ void dataSetChanged() { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (!lp.isDecor) { - lp.widthFactor = 0.f; lp.heightFactor = 0.f; } } @@ -905,12 +932,15 @@ void populate() { void populate(int newCurrentItem) { ItemInfo oldCurInfo = null; + int focusDirection = View.FOCUS_FORWARD; if (mCurItem != newCurrentItem) { + focusDirection = mCurItem < newCurrentItem ? View.FOCUS_DOWN : View.FOCUS_UP; oldCurInfo = infoForPosition(mCurItem); mCurItem = newCurrentItem; } if (mAdapter == null) { + sortChildDrawingOrder(); return; } @@ -920,6 +950,7 @@ void populate(int newCurrentItem) { // that position, avoiding glitches from happening at that point. if (mPopulatePending) { if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); + sortChildDrawingOrder(); return; } @@ -937,6 +968,21 @@ void populate(int newCurrentItem) { final int N = mAdapter.getCount(); final int endPos = Math.min(N-1, mCurItem + pageLimit); + if (N != mExpectedAdapterCount) { + String resName; + try { + resName = getResources().getResourceName(getId()); + } catch (Resources.NotFoundException e) { + resName = Integer.toHexString(getId()); + } + throw new IllegalStateException("The application's PagerAdapter changed the adapter's" + + " contents without calling PagerAdapter#notifyDataSetChanged!" + + " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N + + " Pager id: " + resName + + " Pager class: " + getClass() + + " Problematic adapter: " + mAdapter.getClass()); + } + // Locate the currently focused item or add it if needed. int curIndex = -1; ItemInfo curItem = null; @@ -959,10 +1005,12 @@ void populate(int newCurrentItem) { float extraHeightLeft = 0f; int itemIndex = curIndex - 1; ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; - final float topHeightNeeded = 2.f - curItem.heightFactor; - + final int clientHeight = getClientHeight(); + final float topHeightNeeded = clientHeight <= 0 ? 0 : + 2.f - curItem.heightFactor + (float) getPaddingTop() / (float) clientHeight; + for (int pos = mCurItem - 1; pos >= 0; pos--) { - if (extraHeightLeft >= topHeightNeeded && pos < startPos) { + if ((extraHeightLeft >= topHeightNeeded)) && pos < startPos) { if (ii == null) { break; } @@ -993,8 +1041,12 @@ void populate(int newCurrentItem) { itemIndex = curIndex + 1; if(extraHeightBottom < 2.f) { ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + final float rightWidthNeeded = clientWidth <= 0 ? 0 : + (float) getPaddingRight() / (float) clientWidth + 2.f; + final float bottomHeightNeeded = clientHeight <= 0 ? 0 : + (float) getPaddingBottom() / (float) clientHeight + 2.f; for (int pos = mCurItem + 1; pos < N; pos++) { - if(extraHeightBottom >= 2.f && pos > endPos) { + if((extraHeightBottom >= bottomHeightNeeded) && pos > endPos) { if (ii == null) { break; } @@ -1008,13 +1060,13 @@ void populate(int newCurrentItem) { ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; } } else if (ii != null && pos == ii.position) { - extraHeightBottom += ii.heightFactor; + extraHeightBottom += ii.heightFactor; itemIndex++; ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; } else { ii = addNewItem(pos, itemIndex); itemIndex++; - extraHeightBottom += ii.heightFactor; + extraHeightBottom += ii.heightFactor; ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; } } @@ -1036,32 +1088,21 @@ void populate(int newCurrentItem) { // Check width measurement of current pages and drawing sort order. // Update LayoutParams as needed. - final boolean sort = mDrawingOrder != DRAW_ORDER_DEFAULT; - if (sort) { - if (mDrawingOrderedChildren == null) { - mDrawingOrderedChildren = new ArrayListA fake drag can be useful if you want to synchronize the motion of the ViewPager - * with the touch scrolling of another view, while still letting the ViewPager + *
A fake drag can be useful if you want to synchronize the motion of the VerticalViewPager + * with the touch scrolling of another view, while still letting the VerticalViewPager * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. * - *
During a fake drag the ViewPager will ignore all touch events. If a real drag + *
During a fake drag the VerticalViewPager will ignore all touch events. If a real drag
* is already in progress, this method will return false.
*
* @return true if the fake drag began successfully, false if it could not be started.
@@ -2245,7 +2289,7 @@ public boolean beginFakeDrag() {
}
mFakeDragging = true;
setScrollState(SCROLL_STATE_DRAGGING);
- mInitialMotionY = mLastMotionY = 0;
+ mInitialMotionY = mLastMotionY = 0;
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
@@ -2275,7 +2319,7 @@ public void endFakeDrag() {
int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(
velocityTracker, mActivePointerId);
mPopulatePending = true;
- final int height = getHeight();
+ final int height = getClientHeight();
final int scrollY = getScrollY();
final ItemInfo ii = infoForCurrentScrollPosition();
final int currentPage = ii.position;
@@ -2296,7 +2340,6 @@ public void endFakeDrag() {
* @see #beginFakeDrag()
* @see #endFakeDrag()
*/
-// public void fakeDragBy(float xOffset) {
public void fakeDragBy(float yOffset) {
if (!mFakeDragging) {
throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
@@ -2306,7 +2349,7 @@ public void fakeDragBy(float yOffset) {
float oldScrollY = getScrollY();
float scrollY = oldScrollY - yOffset;
- final int height = getHeight();
+ final int height = getClientHeight();
float topBound = height * mFirstOffset;
float bottomBound = height * mLastOffset;
@@ -2359,7 +2402,7 @@ private void onSecondaryPointerUp(MotionEvent ev) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionY = MotionEventCompat.getY(ev, newPointerIndex);
+ mLastMotionY = MotionEventCompat.getY(ev, newPointerIndex);
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
if (mVelocityTracker != null) {
mVelocityTracker.clear();
@@ -2392,8 +2435,24 @@ private void setScrollingCacheEnabled(boolean enabled) {
}
}
+ public boolean canScrollVertically1(int direction) {
+ if (mAdapter == null) {
+ return false;
+ }
+
+ final int height = getClientHeight();
+ final int scrollY = getScrollY();
+ if (direction < 0) {
+ return (scrollY > (int) (height * mFirstOffset));
+ } else if (direction > 0) {
+ return (scrollY < (int) (height * mLastOffset));
+ } else {
+ return false;
+ }
+ }
+
/**
- * Tests scrollability within child views of v given a delta of dx.
+ * Tests scrollability within child views of v given a delta of dy.
*
* @param v View to test for horizontal scrollability
* @param checkV Whether the view v passed should itself be checked for scrollability (true),
@@ -2401,7 +2460,7 @@ private void setScrollingCacheEnabled(boolean enabled) {
* @param dy Delta scrolled in pixels
* @param x X coordinate of the active touch point
* @param y Y coordinate of the active touch point
- * @return true if child views of v can be scrolled by delta of dy.
+ * @return true if child views of v can be scrolled by delta of dx.
*/
protected boolean canScroll(View v, boolean checkV, int dy, int x, int y) {
if (v instanceof ViewGroup) {
@@ -2423,12 +2482,7 @@ protected boolean canScroll(View v, boolean checkV, int dy, int x, int y) {
}
}
- // to vertical scroll inner WebViews for Froyo+
- if (v instanceof ExtendedWebView) {
- return ((ExtendedWebView) v).canScrollVertical(-dy);
- } else {
- return checkV && ViewCompat.canScrollVertically(v, -dy);
- }
+ return checkV && ViewCompat.canScrollVertically(v, -dy);
}
@Override
@@ -2452,9 +2506,15 @@ public boolean executeKeyEvent(KeyEvent event) {
case KeyEvent.KEYCODE_DPAD_LEFT:
handled = arrowScroll(FOCUS_LEFT);
break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ handled = arrowScroll(FOCUS_UP);
+ break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
handled = arrowScroll(FOCUS_RIGHT);
break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ handled = arrowScroll(FOCUS_DOWN);
+ break;
case KeyEvent.KEYCODE_TAB:
if (Build.VERSION.SDK_INT >= 11) {
// The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD
@@ -2473,7 +2533,30 @@ public boolean executeKeyEvent(KeyEvent event) {
public boolean arrowScroll(int direction) {
View currentFocused = findFocus();
- if (currentFocused == this) currentFocused = null;
+ if (currentFocused == this) {
+ currentFocused = null;
+ } else if (currentFocused != null) {
+ boolean isChild = false;
+ for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
+ parent = parent.getParent()) {
+ if (parent == this) {
+ isChild = true;
+ break;
+ }
+ }
+ if (!isChild) {
+ // This would cause the focus search down below to fail in fun ways.
+ final StringBuilder sb = new StringBuilder();
+ sb.append(currentFocused.getClass().getSimpleName());
+ for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
+ parent = parent.getParent()) {
+ sb.append(" => ").append(parent.getClass().getSimpleName());
+ }
+ Log.e(TAG, "arrowScroll tried to find focus based on non-child " +
+ "current focused view " + sb.toString());
+ currentFocused = null;
+ }
+ }
boolean handled = false;
@@ -2481,9 +2564,8 @@ public boolean arrowScroll(int direction) {
direction);
if (nextFocused != null && nextFocused != currentFocused) {
if(direction == View.FOCUS_UP) {
- // If there is nothing to the left, or this is causing us to
- // jump to the right, then what we really want to do is page left.
-
+ // If there is nothing up, or this is causing us to
+ // jump down, then what we really want to do is page down.
final int nextUp = getChildRectInPagerCoordinates(mTempRect, nextFocused).top;
final int currUp = getChildRectInPagerCoordinates(mTempRect, currentFocused).top;
@@ -2492,10 +2574,9 @@ public boolean arrowScroll(int direction) {
} else {
handled = nextFocused.requestFocus();
}
- } else if (direction == View.FOCUS_RIGHT) {
- // If there is nothing to the right, or this is causing us to
- // jump to the left, then what we really want to do is page right.
-
+ } else if (direction == View.FOCUS_DOWN) {
+ // If there is nothing to the bottom, or this is causing us to
+ // jump up, then what we really want to do is page bottom.
final int nextDown = getChildRectInPagerCoordinates(mTempRect, nextFocused).bottom;
final int currDown = getChildRectInPagerCoordinates(mTempRect, currentFocused).bottom;
if (currentFocused != null && nextDown <= currDown) {
@@ -2504,10 +2585,10 @@ public boolean arrowScroll(int direction) {
handled = nextFocused.requestFocus();
}
}
- } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {
+ } else if (direction == FOCUS_UP || direction == FOCUS_BACKWARD) {
// Trying to move left and nothing there; try to page.
handled = pageUp();
- } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {
+ } else if (direction == FOCUS_DOWN || direction == FOCUS_FORWARD) {
// Trying to move right and nothing there; try to page.
handled = pageDown();
}
@@ -2550,7 +2631,7 @@ boolean pageUp() {
}
return false;
}
-
+
boolean pageDown() {
if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) {
setCurrentItem(mCurItem+1, true);
@@ -2609,7 +2690,7 @@ public void addFocusables(ArrayList