diff options
author | Adam Powell <adamp@google.com> | 2012-05-07 15:17:20 -0700 |
---|---|---|
committer | Adam Powell <adamp@google.com> | 2012-05-07 16:48:32 -0700 |
commit | e69370e16852c576890dd70733ad40669fd9367e (patch) | |
tree | ff51ee906f1e9e687809e83fa17bb01c6ef11b5f /core | |
parent | 9d7bbcb89a3f14331c55ed2bbdcf768a4aa91cc1 (diff) | |
download | frameworks_base-e69370e16852c576890dd70733ad40669fd9367e.zip frameworks_base-e69370e16852c576890dd70733ad40669fd9367e.tar.gz frameworks_base-e69370e16852c576890dd70733ad40669fd9367e.tar.bz2 |
Fix misc. bugs in AbsListView smooth scrolling.
Handle the edge cases a bit better. Deal with padding. If a smooth
scroll begins, the list is empty, but a data change is pending, try
again on the next looper pass.
Bug 6453837
Bug 6434713
Change-Id: I53f22ebacdcbc5d981a6c8055c4fd3fc1ef140f6
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/widget/AbsListView.java | 104 |
1 files changed, 93 insertions, 11 deletions
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 449870e..5fe0f5f 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3985,7 +3985,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } class PositionScroller implements Runnable { - private static final int SCROLL_DURATION = 400; + private static final int SCROLL_DURATION = 200; private static final int MOVE_DOWN_POS = 1; private static final int MOVE_UP_POS = 2; @@ -4006,21 +4006,35 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength(); } - void start(int position) { + void start(final int position) { stop(); + final int childCount = getChildCount(); + if (childCount == 0) { + // Can't scroll without children. + if (mDataChanged) { + // But we might have something in a minute. + post(new Runnable() { + @Override public void run() { + start(position); + } + }); + } + return; + } + final int firstPos = mFirstPosition; - final int lastPos = firstPos + getChildCount() - 1; + final int lastPos = firstPos + childCount - 1; int viewTravelCount; - if (position <= firstPos) { + if (position < firstPos) { viewTravelCount = firstPos - position + 1; mMode = MOVE_UP_POS; - } else if (position >= lastPos) { + } else if (position > lastPos) { viewTravelCount = position - lastPos + 1; mMode = MOVE_DOWN_POS; } else { - // Already on screen, nothing to do + scrollToVisible(position, INVALID_POSITION, SCROLL_DURATION); return; } @@ -4036,7 +4050,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te postOnAnimation(this); } - void start(int position, int boundPosition) { + void start(final int position, final int boundPosition) { stop(); if (boundPosition == INVALID_POSITION) { @@ -4044,11 +4058,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return; } + final int childCount = getChildCount(); + if (childCount == 0) { + // Can't scroll without children. + if (mDataChanged) { + // But we might have something in a minute. + post(new Runnable() { + @Override public void run() { + start(position, boundPosition); + } + }); + } + return; + } + final int firstPos = mFirstPosition; - final int lastPos = firstPos + getChildCount() - 1; + final int lastPos = firstPos + childCount - 1; int viewTravelCount; - if (position <= firstPos) { + if (position < firstPos) { final int boundPosFromLast = lastPos - boundPosition; if (boundPosFromLast < 1) { // Moving would shift our bound position off the screen. Abort. @@ -4064,7 +4092,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te viewTravelCount = posTravel; mMode = MOVE_UP_POS; } - } else if (position >= lastPos) { + } else if (position > lastPos) { final int boundPosFromFirst = boundPosition - firstPos; if (boundPosFromFirst < 1) { // Moving would shift our bound position off the screen. Abort. @@ -4081,7 +4109,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mMode = MOVE_DOWN_POS; } } else { - // Already on screen, nothing to do + scrollToVisible(position, boundPosition, SCROLL_DURATION); return; } @@ -4137,6 +4165,60 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te postOnAnimation(this); } + /** + * Scroll such that targetPos is in the visible padded region without scrolling + * boundPos out of view. Assumes targetPos is onscreen. + */ + void scrollToVisible(int targetPos, int boundPos, int duration) { + final int firstPos = mFirstPosition; + final int childCount = getChildCount(); + final int lastPos = firstPos + childCount - 1; + final int paddedTop = mListPadding.top; + final int paddedBottom = getHeight() - mListPadding.bottom; + + if (targetPos < firstPos || targetPos > lastPos) { + Log.w(TAG, "scrollToVisible called with targetPos " + targetPos + + " not visible [" + firstPos + ", " + lastPos + "]"); + } + if (boundPos < firstPos || boundPos > lastPos) { + // boundPos doesn't matter, it's already offscreen. + boundPos = INVALID_POSITION; + } + + final View targetChild = getChildAt(targetPos - firstPos); + final int targetTop = targetChild.getTop(); + final int targetBottom = targetChild.getBottom(); + int scrollBy = 0; + + if (targetBottom > paddedBottom) { + scrollBy = targetBottom - paddedBottom; + } + if (targetTop < paddedTop) { + scrollBy = targetTop - paddedTop; + } + + if (scrollBy == 0) { + return; + } + + if (boundPos >= 0) { + final View boundChild = getChildAt(boundPos - firstPos); + final int boundTop = boundChild.getTop(); + final int boundBottom = boundChild.getBottom(); + final int absScroll = Math.abs(scrollBy); + + if (scrollBy < 0 && boundBottom + absScroll > paddedBottom) { + // Don't scroll the bound view off the bottom of the screen. + scrollBy = Math.max(0, boundBottom - paddedBottom); + } else if (scrollBy > 0 && boundTop - absScroll < paddedTop) { + // Don't scroll the bound view off the top of the screen. + scrollBy = Math.min(0, boundTop - paddedTop); + } + } + + smoothScrollBy(scrollBy, duration); + } + void stop() { removeCallbacks(this); } |