Fling while overscrolled: ScrollView/HorizontalScrollView
Bug: 186430321 ScrollView and HorizontalScrollView was not allowing a fling effect while overscrolling. This adds the ability to fling while overscrolling. Test: new test Test: manual ApiDemos Change-Id: Iebd402ff0f5b6f16518ecc5403e085cb58de5976
This commit is contained in:
@@ -47,6 +47,7 @@ import android.view.animation.AnimationUtils;
|
||||
import android.view.inspector.InspectableProperty;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -86,19 +87,23 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
*
|
||||
* Even though this field is practically final, we cannot make it final because there are apps
|
||||
* setting it via reflection and they need to keep working until they target Q.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124053130)
|
||||
private EdgeEffect mEdgeGlowLeft;
|
||||
@VisibleForTesting
|
||||
public EdgeEffect mEdgeGlowLeft;
|
||||
|
||||
/**
|
||||
* Tracks the state of the bottom edge glow.
|
||||
*
|
||||
* Even though this field is practically final, we cannot make it final because there are apps
|
||||
* setting it via reflection and they need to keep working until they target Q.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052619)
|
||||
private EdgeEffect mEdgeGlowRight;
|
||||
@VisibleForTesting
|
||||
public EdgeEffect mEdgeGlowRight;
|
||||
|
||||
/**
|
||||
* Position of the last motion event.
|
||||
@@ -774,11 +779,8 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
|
||||
// Calling overScrollBy will call onOverScrolled, which
|
||||
// calls onScrollChanged if applicable.
|
||||
if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
|
||||
mOverscrollDistance, 0, true)) {
|
||||
// Break our velocity if we hit a scroll barrier.
|
||||
mVelocityTracker.clear();
|
||||
}
|
||||
overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
|
||||
mOverscrollDistance, 0, true);
|
||||
|
||||
if (canOverscroll && deltaX != 0f) {
|
||||
final int pulledToX = oldX + deltaX;
|
||||
@@ -1737,23 +1739,31 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
public void fling(int velocityX) {
|
||||
if (getChildCount() > 0) {
|
||||
int width = getWidth() - mPaddingRight - mPaddingLeft;
|
||||
int right = getChildAt(0).getWidth();
|
||||
int right = getChildAt(0).getRight() - mPaddingLeft;
|
||||
|
||||
mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0,
|
||||
Math.max(0, right - width), 0, 0, width/2, 0);
|
||||
int maxScroll = Math.max(0, right - width);
|
||||
|
||||
final boolean movingRight = velocityX > 0;
|
||||
if (mScrollX == 0 && !mEdgeGlowLeft.isFinished()) {
|
||||
mEdgeGlowLeft.onAbsorb(-velocityX);
|
||||
} else if (mScrollX == maxScroll && !mEdgeGlowRight.isFinished()) {
|
||||
mEdgeGlowRight.onAbsorb(velocityX);
|
||||
} else {
|
||||
mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0,
|
||||
maxScroll, 0, 0, width / 2, 0);
|
||||
|
||||
View currentFocused = findFocus();
|
||||
View newFocused = findFocusableViewInMyBounds(movingRight,
|
||||
mScroller.getFinalX(), currentFocused);
|
||||
final boolean movingRight = velocityX > 0;
|
||||
|
||||
if (newFocused == null) {
|
||||
newFocused = this;
|
||||
}
|
||||
View currentFocused = findFocus();
|
||||
View newFocused = findFocusableViewInMyBounds(movingRight,
|
||||
mScroller.getFinalX(), currentFocused);
|
||||
|
||||
if (newFocused != currentFocused) {
|
||||
newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT);
|
||||
if (newFocused == null) {
|
||||
newFocused = this;
|
||||
}
|
||||
|
||||
if (newFocused != currentFocused) {
|
||||
newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
postInvalidateOnAnimation();
|
||||
|
||||
@@ -49,6 +49,7 @@ import android.view.animation.AnimationUtils;
|
||||
import android.view.inspector.InspectableProperty;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -95,20 +96,24 @@ public class ScrollView extends FrameLayout {
|
||||
*
|
||||
* Even though this field is practically final, we cannot make it final because there are apps
|
||||
* setting it via reflection and they need to keep working until they target Q.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768600)
|
||||
private EdgeEffect mEdgeGlowTop;
|
||||
@VisibleForTesting
|
||||
public EdgeEffect mEdgeGlowTop;
|
||||
|
||||
/**
|
||||
* Tracks the state of the bottom edge glow.
|
||||
*
|
||||
* Even though this field is practically final, we cannot make it final because there are apps
|
||||
* setting it via reflection and they need to keep working until they target Q.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769386)
|
||||
private EdgeEffect mEdgeGlowBottom;
|
||||
@VisibleForTesting
|
||||
public EdgeEffect mEdgeGlowBottom;
|
||||
|
||||
/**
|
||||
* Position of the last motion event.
|
||||
@@ -1791,9 +1796,15 @@ public class ScrollView extends FrameLayout {
|
||||
final boolean canFling = (mScrollY > 0 || velocityY > 0) &&
|
||||
(mScrollY < getScrollRange() || velocityY < 0);
|
||||
if (!dispatchNestedPreFling(0, velocityY)) {
|
||||
dispatchNestedFling(0, velocityY, canFling);
|
||||
final boolean consumed = dispatchNestedFling(0, velocityY, canFling);
|
||||
if (canFling) {
|
||||
fling(velocityY);
|
||||
} else if (!consumed) {
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onAbsorb(-velocityY);
|
||||
} else if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onAbsorb(velocityY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user