summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorAdam Powell <adamp@google.com>2012-05-07 15:17:20 -0700
committerAdam Powell <adamp@google.com>2012-05-07 16:48:32 -0700
commite69370e16852c576890dd70733ad40669fd9367e (patch)
treeff51ee906f1e9e687809e83fa17bb01c6ef11b5f /core
parent9d7bbcb89a3f14331c55ed2bbdcf768a4aa91cc1 (diff)
downloadframeworks_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.java104
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);
}