Merge "ListView implementation for stretch overscroll." into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d90f98587f
@@ -715,7 +715,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769408)
|
||||
private EdgeEffect mEdgeGlowTop = new EdgeEffect(mContext);
|
||||
private EdgeEffect mEdgeGlowTop;
|
||||
|
||||
/**
|
||||
* Tracks the state of the bottom edge glow.
|
||||
@@ -725,7 +725,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768444)
|
||||
private EdgeEffect mEdgeGlowBottom = new EdgeEffect(mContext);
|
||||
private EdgeEffect mEdgeGlowBottom;
|
||||
|
||||
/**
|
||||
* An estimate of how many pixels are between the top of the list and
|
||||
@@ -847,6 +847,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
|
||||
public AbsListView(Context context) {
|
||||
super(context);
|
||||
mEdgeGlowBottom = new EdgeEffect(context);
|
||||
mEdgeGlowTop = new EdgeEffect(context);
|
||||
initAbsListView();
|
||||
|
||||
mOwnerThread = Thread.currentThread();
|
||||
@@ -867,6 +869,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
|
||||
public AbsListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
mEdgeGlowBottom = new EdgeEffect(context, attrs);
|
||||
mEdgeGlowTop = new EdgeEffect(context, attrs);
|
||||
initAbsListView();
|
||||
|
||||
mOwnerThread = Thread.currentThread();
|
||||
@@ -3584,6 +3588,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY;
|
||||
int lastYCorrection = 0;
|
||||
|
||||
// First allow releasing existing overscroll effect:
|
||||
incrementalDeltaY = releaseGlow(incrementalDeltaY, x);
|
||||
|
||||
if (mTouchMode == TOUCH_MODE_SCROLL) {
|
||||
if (PROFILE_SCROLLING) {
|
||||
if (!mScrollProfilingStarted) {
|
||||
@@ -3666,14 +3673,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
mTouchMode = TOUCH_MODE_OVERSCROLL;
|
||||
}
|
||||
if (incrementalDeltaY > 0) {
|
||||
mEdgeGlowTop.onPull((float) -overscroll / getHeight(),
|
||||
mEdgeGlowTop.onPullDistance((float) -overscroll / getHeight(),
|
||||
(float) x / getWidth());
|
||||
if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onRelease();
|
||||
}
|
||||
invalidateTopGlow();
|
||||
} else if (incrementalDeltaY < 0) {
|
||||
mEdgeGlowBottom.onPull((float) overscroll / getHeight(),
|
||||
mEdgeGlowBottom.onPullDistance((float) overscroll / getHeight(),
|
||||
1.f - (float) x / getWidth());
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onRelease();
|
||||
@@ -3713,14 +3720,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
||||
!contentFits())) {
|
||||
if (rawDeltaY > 0) {
|
||||
mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(),
|
||||
mEdgeGlowTop.onPullDistance((float) overScrollDistance / getHeight(),
|
||||
(float) x / getWidth());
|
||||
if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onRelease();
|
||||
}
|
||||
invalidateTopGlow();
|
||||
} else if (rawDeltaY < 0) {
|
||||
mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(),
|
||||
mEdgeGlowBottom.onPullDistance(
|
||||
(float) -overScrollDistance / getHeight(),
|
||||
1.f - (float) x / getWidth());
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onRelease();
|
||||
@@ -3757,6 +3765,44 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the edge glow is currently active, this consumes part or all of deltaY
|
||||
* on the edge glow.
|
||||
*
|
||||
* @param deltaY The pointer motion, in pixels, in the vertical direction, positive
|
||||
* for moving down and negative for moving up.
|
||||
* @param x The horizontal position of the pointer.
|
||||
* @return The remainder of <code>deltaY</code> that has not been consumed by the
|
||||
* edge glow.
|
||||
*/
|
||||
private int releaseGlow(int deltaY, int x) {
|
||||
// First allow releasing existing overscroll effect:
|
||||
float consumed = 0;
|
||||
if (mEdgeGlowTop.getDistance() != 0) {
|
||||
consumed = mEdgeGlowTop.onPullDistance((float) deltaY / getHeight(),
|
||||
(float) x / getWidth());
|
||||
if (consumed != 0f) {
|
||||
invalidateTopGlow();
|
||||
}
|
||||
} else if (mEdgeGlowBottom.getDistance() != 0) {
|
||||
consumed = -mEdgeGlowBottom.onPullDistance((float) -deltaY / getHeight(),
|
||||
1f - (float) x / getWidth());
|
||||
if (consumed != 0f) {
|
||||
invalidateBottomGlow();
|
||||
}
|
||||
}
|
||||
int pixelsConsumed = Math.round(consumed * getHeight());
|
||||
return deltaY - pixelsConsumed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if either the top or bottom edge glow is currently active or
|
||||
* <code>false</code> if it has no value to release.
|
||||
*/
|
||||
private boolean isGlowActive() {
|
||||
return mEdgeGlowBottom.getDistance() != 0 || mEdgeGlowTop.getDistance() != 0;
|
||||
}
|
||||
|
||||
private void invalidateTopGlow() {
|
||||
if (!shouldDisplayEdgeEffects()) {
|
||||
return;
|
||||
@@ -3926,7 +3972,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
|
||||
if (mTouchMode == TOUCH_MODE_OVERFLING) {
|
||||
// Stopped the fling. It is a scroll.
|
||||
mFlingRunnable.endFling();
|
||||
if (mFlingRunnable != null) {
|
||||
mFlingRunnable.endFling();
|
||||
}
|
||||
if (mPositionScroller != null) {
|
||||
mPositionScroller.stop();
|
||||
}
|
||||
@@ -3936,6 +3984,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
mLastY = mMotionY;
|
||||
mMotionCorrection = 0;
|
||||
mDirection = 0;
|
||||
stopEdgeGlowRecede(ev.getX());
|
||||
} else {
|
||||
final int x = (int) ev.getX();
|
||||
final int y = (int) ev.getY();
|
||||
@@ -3948,7 +3997,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
mTouchMode = TOUCH_MODE_SCROLL;
|
||||
mMotionCorrection = 0;
|
||||
motionPosition = findMotionRow(y);
|
||||
mFlingRunnable.flywheelTouch();
|
||||
if (mFlingRunnable != null) {
|
||||
mFlingRunnable.flywheelTouch();
|
||||
}
|
||||
stopEdgeGlowRecede(x);
|
||||
} else if ((motionPosition >= 0) && getAdapter().isEnabled(motionPosition)) {
|
||||
// User clicked on an actual view (and was not stopping a
|
||||
// fling). It might be a click or a scroll. Assume it is a
|
||||
@@ -3984,6 +4036,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
}
|
||||
}
|
||||
|
||||
private void stopEdgeGlowRecede(float x) {
|
||||
if (mEdgeGlowTop.getDistance() != 0) {
|
||||
mEdgeGlowTop.onPullDistance(0, x / getWidth());
|
||||
}
|
||||
if (mEdgeGlowBottom.getDistance() != 0) {
|
||||
mEdgeGlowBottom.onPullDistance(0, x / getWidth());
|
||||
}
|
||||
}
|
||||
|
||||
private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
|
||||
if (mHasPerformedLongPress) {
|
||||
// Consume all move events following a successful long press.
|
||||
@@ -4489,73 +4550,76 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
}
|
||||
|
||||
switch (actionMasked) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
int touchMode = mTouchMode;
|
||||
if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
|
||||
mMotionCorrection = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
final int x = (int) ev.getX();
|
||||
final int y = (int) ev.getY();
|
||||
mActivePointerId = ev.getPointerId(0);
|
||||
|
||||
int motionPosition = findMotionRow(y);
|
||||
if (touchMode != TOUCH_MODE_FLING && motionPosition >= 0) {
|
||||
// User clicked on an actual view (and was not stopping a fling).
|
||||
// Remember where the motion event started
|
||||
v = getChildAt(motionPosition - mFirstPosition);
|
||||
mMotionViewOriginalTop = v.getTop();
|
||||
mMotionX = x;
|
||||
mMotionY = y;
|
||||
mMotionPosition = motionPosition;
|
||||
mTouchMode = TOUCH_MODE_DOWN;
|
||||
clearScrollingCache();
|
||||
}
|
||||
mLastY = Integer.MIN_VALUE;
|
||||
initOrResetVelocityTracker();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
mNestedYOffset = 0;
|
||||
startNestedScroll(SCROLL_AXIS_VERTICAL);
|
||||
if (touchMode == TOUCH_MODE_FLING) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
switch (mTouchMode) {
|
||||
case TOUCH_MODE_DOWN:
|
||||
int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
if (pointerIndex == -1) {
|
||||
pointerIndex = 0;
|
||||
mActivePointerId = ev.getPointerId(pointerIndex);
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
int touchMode = mTouchMode;
|
||||
if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
|
||||
mMotionCorrection = 0;
|
||||
return true;
|
||||
}
|
||||
final int y = (int) ev.getY(pointerIndex);
|
||||
initVelocityTrackerIfNotExists();
|
||||
|
||||
final int x = (int) ev.getX();
|
||||
final int y = (int) ev.getY();
|
||||
mActivePointerId = ev.getPointerId(0);
|
||||
|
||||
int motionPosition = findMotionRow(y);
|
||||
if (isGlowActive()) {
|
||||
// Pressed during edge effect, so this is considered the same as a fling catch.
|
||||
mTouchMode = TOUCH_MODE_FLING;
|
||||
} else if (touchMode != TOUCH_MODE_FLING && motionPosition >= 0) {
|
||||
// User clicked on an actual view (and was not stopping a fling).
|
||||
// Remember where the motion event started
|
||||
v = getChildAt(motionPosition - mFirstPosition);
|
||||
mMotionViewOriginalTop = v.getTop();
|
||||
mMotionX = x;
|
||||
mMotionY = y;
|
||||
mMotionPosition = motionPosition;
|
||||
mTouchMode = TOUCH_MODE_DOWN;
|
||||
clearScrollingCache();
|
||||
}
|
||||
mLastY = Integer.MIN_VALUE;
|
||||
initOrResetVelocityTracker();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
|
||||
mNestedYOffset = 0;
|
||||
startNestedScroll(SCROLL_AXIS_VERTICAL);
|
||||
if (touchMode == TOUCH_MODE_FLING) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP: {
|
||||
mTouchMode = TOUCH_MODE_REST;
|
||||
mActivePointerId = INVALID_POINTER;
|
||||
recycleVelocityTracker();
|
||||
reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
|
||||
stopNestedScroll();
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
switch (mTouchMode) {
|
||||
case TOUCH_MODE_DOWN:
|
||||
int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
if (pointerIndex == -1) {
|
||||
pointerIndex = 0;
|
||||
mActivePointerId = ev.getPointerId(pointerIndex);
|
||||
}
|
||||
final int y = (int) ev.getY(pointerIndex);
|
||||
initVelocityTrackerIfNotExists();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP: {
|
||||
onSecondaryPointerUp(ev);
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP: {
|
||||
mTouchMode = TOUCH_MODE_REST;
|
||||
mActivePointerId = INVALID_POINTER;
|
||||
recycleVelocityTracker();
|
||||
reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
|
||||
stopNestedScroll();
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP: {
|
||||
onSecondaryPointerUp(ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user