Merge "Fix janky programmatic ListView scrolling" into jb-dev

This commit is contained in:
Adam Powell
2012-04-26 11:14:02 -07:00
committed by Android (Google) Code Review
2 changed files with 41 additions and 18 deletions

View File

@@ -58,6 +58,8 @@ import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -659,6 +661,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
private int mLastHandledItemCount;
/**
* Used for smooth scrolling at a consistent rate
*/
static final Interpolator sLinearInterpolator = new LinearInterpolator();
/**
* Interface definition for a callback to be invoked when the list or grid
* has been scrolled.
@@ -3753,6 +3760,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
void start(int initialVelocity) {
int initialY = initialVelocity < 0 ? Integer.MAX_VALUE : 0;
mLastFlingY = initialY;
mScroller.setInterpolator(null);
mScroller.fling(0, initialY, 0, initialVelocity,
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
mTouchMode = TOUCH_MODE_FLING;
@@ -3782,6 +3790,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
void startOverfling(int initialVelocity) {
mScroller.setInterpolator(null);
mScroller.fling(0, mScrollY, 0, initialVelocity, 0, 0,
Integer.MIN_VALUE, Integer.MAX_VALUE, 0, getHeight());
mTouchMode = TOUCH_MODE_OVERFLING;
@@ -3811,9 +3820,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
postOnAnimation(this);
}
void startScroll(int distance, int duration) {
void startScroll(int distance, int duration, boolean linear) {
int initialY = distance < 0 ? Integer.MAX_VALUE : 0;
mLastFlingY = initialY;
mScroller.setInterpolator(linear ? sLinearInterpolator : null);
mScroller.startScroll(0, initialY, 0, distance, duration);
mTouchMode = TOUCH_MODE_FLING;
postOnAnimation(this);
@@ -4107,14 +4117,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} else {
// On-screen, just scroll.
final int targetTop = getChildAt(position - firstPos).getTop();
smoothScrollBy(targetTop - offset, duration);
smoothScrollBy(targetTop - offset, duration, true);
return;
}
// Estimate how many screens we should travel
final float screenTravelCount = (float) viewTravelCount / childCount;
mScrollDuration = screenTravelCount < 1 ? (int) (screenTravelCount * duration) :
(int) (duration / screenTravelCount);
mScrollDuration = screenTravelCount < 1 ?
duration : (int) (duration / screenTravelCount);
mLastSeenPos = INVALID_POSITION;
postOnAnimation(this);
@@ -4151,7 +4161,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
Math.max(mListPadding.bottom, mExtraScroll) : mListPadding.bottom;
final int scrollBy = lastViewHeight - lastViewPixelsShowing + extraScroll;
smoothScrollBy(scrollBy, mScrollDuration);
smoothScrollBy(scrollBy, mScrollDuration, true);
mLastSeenPos = lastPos;
if (lastPos < mTargetPos) {
@@ -4182,14 +4192,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final int extraScroll = Math.max(mListPadding.bottom, mExtraScroll);
if (nextPos < mBoundPos) {
smoothScrollBy(Math.max(0, nextViewHeight + nextViewTop - extraScroll),
mScrollDuration);
mScrollDuration, true);
mLastSeenPos = nextPos;
postOnAnimation(this);
} else {
if (nextViewTop > extraScroll) {
smoothScrollBy(nextViewTop - extraScroll, mScrollDuration);
smoothScrollBy(nextViewTop - extraScroll, mScrollDuration, true);
}
}
break;
@@ -4210,7 +4220,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final int extraScroll = firstPos > 0 ?
Math.max(mExtraScroll, mListPadding.top) : mListPadding.top;
smoothScrollBy(firstViewTop - extraScroll, mScrollDuration);
smoothScrollBy(firstViewTop - extraScroll, mScrollDuration, true);
mLastSeenPos = firstPos;
@@ -4229,7 +4239,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (lastPos == mLastSeenPos) {
// No new views, let things keep going.
post(this);
postOnAnimation(this);
return;
}
@@ -4240,13 +4250,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final int extraScroll = Math.max(mListPadding.top, mExtraScroll);
mLastSeenPos = lastPos;
if (lastPos > mBoundPos) {
smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration);
smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration, true);
postOnAnimation(this);
} else {
final int bottom = listHeight - extraScroll;
final int lastViewBottom = lastViewTop + lastViewHeight;
if (bottom > lastViewBottom) {
smoothScrollBy(-(bottom - lastViewBottom), mScrollDuration);
smoothScrollBy(-(bottom - lastViewBottom), mScrollDuration, true);
}
}
break;
@@ -4255,7 +4265,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
case MOVE_OFFSET: {
if (mLastSeenPos == firstPos) {
// No new views, let things keep going.
post(this);
postOnAnimation(this);
return;
}
@@ -4277,17 +4287,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final float modifier = Math.min(Math.abs(screenTravelCount), 1.f);
if (position < firstPos) {
smoothScrollBy((int) (-getHeight() * modifier), mScrollDuration);
final int distance = (int) (-getHeight() * modifier);
final int duration = (int) (mScrollDuration * modifier);
smoothScrollBy(distance, duration, true);
postOnAnimation(this);
} else if (position > lastPos) {
smoothScrollBy((int) (getHeight() * modifier), mScrollDuration);
final int distance = (int) (getHeight() * modifier);
final int duration = (int) (mScrollDuration * modifier);
smoothScrollBy(distance, duration, true);
postOnAnimation(this);
} else {
// On-screen, just scroll.
final int targetTop = getChildAt(position - firstPos).getTop();
final int distance = targetTop - mOffsetFromTop;
smoothScrollBy(distance,
(int) (mScrollDuration * ((float) distance / getHeight())));
final int duration = (int) (mScrollDuration *
((float) Math.abs(distance) / getHeight()));
smoothScrollBy(distance, duration, true);
}
break;
}
@@ -4393,6 +4408,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @param duration Duration of the scroll animation in milliseconds.
*/
public void smoothScrollBy(int distance, int duration) {
smoothScrollBy(distance, duration, false);
}
void smoothScrollBy(int distance, int duration, boolean linear) {
if (mFlingRunnable == null) {
mFlingRunnable = new FlingRunnable();
}
@@ -4414,7 +4433,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
} else {
reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
mFlingRunnable.startScroll(distance, duration);
mFlingRunnable.startScroll(distance, duration, linear);
}
}

View File

@@ -35,7 +35,7 @@ public class OverScroller {
private final SplineOverScroller mScrollerX;
private final SplineOverScroller mScrollerY;
private final Interpolator mInterpolator;
private Interpolator mInterpolator;
private final boolean mFlywheel;
@@ -113,6 +113,10 @@ public class OverScroller {
this(context, interpolator, flywheel);
}
void setInterpolator(Interpolator interpolator) {
mInterpolator = interpolator;
}
/**
* The amount of friction applied to flings. The default value
* is {@link ViewConfiguration#getScrollFriction}.