Skip to content

Commit 6392a36

Browse files
adampAndroid (Google) Code Review
authored andcommitted
Merge "Fix misc. bugs in AbsListView smooth scrolling." into jb-dev
2 parents 401d93f + e69370e commit 6392a36

File tree

1 file changed

+93
-11
lines changed

1 file changed

+93
-11
lines changed

core/java/android/widget/AbsListView.java

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3985,7 +3985,7 @@ public void run() {
39853985
}
39863986

39873987
class PositionScroller implements Runnable {
3988-
private static final int SCROLL_DURATION = 400;
3988+
private static final int SCROLL_DURATION = 200;
39893989

39903990
private static final int MOVE_DOWN_POS = 1;
39913991
private static final int MOVE_UP_POS = 2;
@@ -4006,21 +4006,35 @@ class PositionScroller implements Runnable {
40064006
mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength();
40074007
}
40084008

4009-
void start(int position) {
4009+
void start(final int position) {
40104010
stop();
40114011

4012+
final int childCount = getChildCount();
4013+
if (childCount == 0) {
4014+
// Can't scroll without children.
4015+
if (mDataChanged) {
4016+
// But we might have something in a minute.
4017+
post(new Runnable() {
4018+
@Override public void run() {
4019+
start(position);
4020+
}
4021+
});
4022+
}
4023+
return;
4024+
}
4025+
40124026
final int firstPos = mFirstPosition;
4013-
final int lastPos = firstPos + getChildCount() - 1;
4027+
final int lastPos = firstPos + childCount - 1;
40144028

40154029
int viewTravelCount;
4016-
if (position <= firstPos) {
4030+
if (position < firstPos) {
40174031
viewTravelCount = firstPos - position + 1;
40184032
mMode = MOVE_UP_POS;
4019-
} else if (position >= lastPos) {
4033+
} else if (position > lastPos) {
40204034
viewTravelCount = position - lastPos + 1;
40214035
mMode = MOVE_DOWN_POS;
40224036
} else {
4023-
// Already on screen, nothing to do
4037+
scrollToVisible(position, INVALID_POSITION, SCROLL_DURATION);
40244038
return;
40254039
}
40264040

@@ -4036,19 +4050,33 @@ void start(int position) {
40364050
postOnAnimation(this);
40374051
}
40384052

4039-
void start(int position, int boundPosition) {
4053+
void start(final int position, final int boundPosition) {
40404054
stop();
40414055

40424056
if (boundPosition == INVALID_POSITION) {
40434057
start(position);
40444058
return;
40454059
}
40464060

4061+
final int childCount = getChildCount();
4062+
if (childCount == 0) {
4063+
// Can't scroll without children.
4064+
if (mDataChanged) {
4065+
// But we might have something in a minute.
4066+
post(new Runnable() {
4067+
@Override public void run() {
4068+
start(position, boundPosition);
4069+
}
4070+
});
4071+
}
4072+
return;
4073+
}
4074+
40474075
final int firstPos = mFirstPosition;
4048-
final int lastPos = firstPos + getChildCount() - 1;
4076+
final int lastPos = firstPos + childCount - 1;
40494077

40504078
int viewTravelCount;
4051-
if (position <= firstPos) {
4079+
if (position < firstPos) {
40524080
final int boundPosFromLast = lastPos - boundPosition;
40534081
if (boundPosFromLast < 1) {
40544082
// Moving would shift our bound position off the screen. Abort.
@@ -4064,7 +4092,7 @@ void start(int position, int boundPosition) {
40644092
viewTravelCount = posTravel;
40654093
mMode = MOVE_UP_POS;
40664094
}
4067-
} else if (position >= lastPos) {
4095+
} else if (position > lastPos) {
40684096
final int boundPosFromFirst = boundPosition - firstPos;
40694097
if (boundPosFromFirst < 1) {
40704098
// Moving would shift our bound position off the screen. Abort.
@@ -4081,7 +4109,7 @@ void start(int position, int boundPosition) {
40814109
mMode = MOVE_DOWN_POS;
40824110
}
40834111
} else {
4084-
// Already on screen, nothing to do
4112+
scrollToVisible(position, boundPosition, SCROLL_DURATION);
40854113
return;
40864114
}
40874115

@@ -4137,6 +4165,60 @@ void startWithOffset(int position, int offset, int duration) {
41374165
postOnAnimation(this);
41384166
}
41394167

4168+
/**
4169+
* Scroll such that targetPos is in the visible padded region without scrolling
4170+
* boundPos out of view. Assumes targetPos is onscreen.
4171+
*/
4172+
void scrollToVisible(int targetPos, int boundPos, int duration) {
4173+
final int firstPos = mFirstPosition;
4174+
final int childCount = getChildCount();
4175+
final int lastPos = firstPos + childCount - 1;
4176+
final int paddedTop = mListPadding.top;
4177+
final int paddedBottom = getHeight() - mListPadding.bottom;
4178+
4179+
if (targetPos < firstPos || targetPos > lastPos) {
4180+
Log.w(TAG, "scrollToVisible called with targetPos " + targetPos +
4181+
" not visible [" + firstPos + ", " + lastPos + "]");
4182+
}
4183+
if (boundPos < firstPos || boundPos > lastPos) {
4184+
// boundPos doesn't matter, it's already offscreen.
4185+
boundPos = INVALID_POSITION;
4186+
}
4187+
4188+
final View targetChild = getChildAt(targetPos - firstPos);
4189+
final int targetTop = targetChild.getTop();
4190+
final int targetBottom = targetChild.getBottom();
4191+
int scrollBy = 0;
4192+
4193+
if (targetBottom > paddedBottom) {
4194+
scrollBy = targetBottom - paddedBottom;
4195+
}
4196+
if (targetTop < paddedTop) {
4197+
scrollBy = targetTop - paddedTop;
4198+
}
4199+
4200+
if (scrollBy == 0) {
4201+
return;
4202+
}
4203+
4204+
if (boundPos >= 0) {
4205+
final View boundChild = getChildAt(boundPos - firstPos);
4206+
final int boundTop = boundChild.getTop();
4207+
final int boundBottom = boundChild.getBottom();
4208+
final int absScroll = Math.abs(scrollBy);
4209+
4210+
if (scrollBy < 0 && boundBottom + absScroll > paddedBottom) {
4211+
// Don't scroll the bound view off the bottom of the screen.
4212+
scrollBy = Math.max(0, boundBottom - paddedBottom);
4213+
} else if (scrollBy > 0 && boundTop - absScroll < paddedTop) {
4214+
// Don't scroll the bound view off the top of the screen.
4215+
scrollBy = Math.min(0, boundTop - paddedTop);
4216+
}
4217+
}
4218+
4219+
smoothScrollBy(scrollBy, duration);
4220+
}
4221+
41404222
void stop() {
41414223
removeCallbacks(this);
41424224
}

0 commit comments

Comments
 (0)