ScrollView and HorizontalScrollView stretch overscroll
Bug: 178807038 Modify ScrollView and HorizontalScrollView to support stretch overscroll. Test: I18820794f2511ff4b7df1c5c6a9d7a2d5fafeaa0 Change-Id: I1370b702ce7331269744033c6acb61b84519c853
This commit is contained in:
@@ -22164,6 +22164,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
* and hardware acceleration.
|
||||
*/
|
||||
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
|
||||
// Clear the overscroll effect:
|
||||
// TODO: Use internal API instead of overriding the existing RenderEffect
|
||||
setRenderEffect(null);
|
||||
|
||||
final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
|
||||
/* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList.
|
||||
*
|
||||
|
||||
@@ -89,7 +89,7 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124053130)
|
||||
private EdgeEffect mEdgeGlowLeft = new EdgeEffect(getContext());
|
||||
private EdgeEffect mEdgeGlowLeft;
|
||||
|
||||
/**
|
||||
* Tracks the state of the bottom edge glow.
|
||||
@@ -98,7 +98,7 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
* setting it via reflection and they need to keep working until they target Q.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052619)
|
||||
private EdgeEffect mEdgeGlowRight = new EdgeEffect(getContext());
|
||||
private EdgeEffect mEdgeGlowRight;
|
||||
|
||||
/**
|
||||
* Position of the last motion event.
|
||||
@@ -186,6 +186,8 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
public HorizontalScrollView(
|
||||
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
mEdgeGlowLeft = new EdgeEffect(context, attrs);
|
||||
mEdgeGlowRight = new EdgeEffect(context, attrs);
|
||||
initScrollView();
|
||||
|
||||
final TypedArray a = context.obtainStyledAttributes(
|
||||
@@ -631,7 +633,15 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
* otherwise don't. mScroller.isFinished should be false when
|
||||
* being flinged.
|
||||
*/
|
||||
mIsBeingDragged = !mScroller.isFinished();
|
||||
mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowLeft.isFinished()
|
||||
|| !mEdgeGlowRight.isFinished();
|
||||
// Catch the edge effect if it is active.
|
||||
if (!mEdgeGlowLeft.isFinished()) {
|
||||
mEdgeGlowLeft.onPullDistance(0f, 1f - ev.getY() / getHeight());
|
||||
}
|
||||
if (!mEdgeGlowRight.isFinished()) {
|
||||
mEdgeGlowRight.onPullDistance(0f, ev.getY() / getHeight());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -675,7 +685,8 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
if (getChildCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
if ((mIsBeingDragged = !mScroller.isFinished())) {
|
||||
if ((mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowRight.isFinished()
|
||||
|| !mEdgeGlowLeft.isFinished())) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
@@ -721,12 +732,26 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
mLastMotionX = x;
|
||||
|
||||
final int oldX = mScrollX;
|
||||
final int oldY = mScrollY;
|
||||
final int range = getScrollRange();
|
||||
final int overscrollMode = getOverScrollMode();
|
||||
final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
|
||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
|
||||
|
||||
final float displacement = ev.getY(activePointerIndex) / getHeight();
|
||||
if (canOverscroll) {
|
||||
int consumed = 0;
|
||||
if (deltaX < 0 && mEdgeGlowRight.getDistance() != 0f) {
|
||||
consumed = Math.round(getHeight()
|
||||
* mEdgeGlowRight.onPullDistance((float) deltaX / getWidth(),
|
||||
displacement));
|
||||
} else if (deltaX > 0 && mEdgeGlowLeft.getDistance() != 0f) {
|
||||
consumed = Math.round(-getHeight()
|
||||
* mEdgeGlowLeft.onPullDistance((float) -deltaX / getWidth(),
|
||||
1 - displacement));
|
||||
}
|
||||
deltaX -= consumed;
|
||||
}
|
||||
|
||||
// Calling overScrollBy will call onOverScrolled, which
|
||||
// calls onScrollChanged if applicable.
|
||||
if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
|
||||
@@ -735,17 +760,17 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
mVelocityTracker.clear();
|
||||
}
|
||||
|
||||
if (canOverscroll) {
|
||||
if (canOverscroll && deltaX != 0f) {
|
||||
final int pulledToX = oldX + deltaX;
|
||||
if (pulledToX < 0) {
|
||||
mEdgeGlowLeft.onPull((float) deltaX / getWidth(),
|
||||
1.f - ev.getY(activePointerIndex) / getHeight());
|
||||
mEdgeGlowLeft.onPullDistance((float) -deltaX / getWidth(),
|
||||
1.f - displacement);
|
||||
if (!mEdgeGlowRight.isFinished()) {
|
||||
mEdgeGlowRight.onRelease();
|
||||
}
|
||||
} else if (pulledToX > range) {
|
||||
mEdgeGlowRight.onPull((float) deltaX / getWidth(),
|
||||
ev.getY(activePointerIndex) / getHeight());
|
||||
mEdgeGlowRight.onPullDistance((float) deltaX / getWidth(),
|
||||
displacement);
|
||||
if (!mEdgeGlowLeft.isFinished()) {
|
||||
mEdgeGlowLeft.onRelease();
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class ScrollView extends FrameLayout {
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768600)
|
||||
private EdgeEffect mEdgeGlowTop = new EdgeEffect(getContext());
|
||||
private EdgeEffect mEdgeGlowTop;
|
||||
|
||||
/**
|
||||
* Tracks the state of the bottom edge glow.
|
||||
@@ -108,7 +108,7 @@ public class ScrollView extends FrameLayout {
|
||||
*/
|
||||
@NonNull
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769386)
|
||||
private EdgeEffect mEdgeGlowBottom = new EdgeEffect(getContext());
|
||||
private EdgeEffect mEdgeGlowBottom;
|
||||
|
||||
/**
|
||||
* Position of the last motion event.
|
||||
@@ -213,6 +213,8 @@ public class ScrollView extends FrameLayout {
|
||||
|
||||
public ScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
mEdgeGlowTop = new EdgeEffect(context, attrs);
|
||||
mEdgeGlowBottom = new EdgeEffect(context, attrs);
|
||||
initScrollView();
|
||||
|
||||
final TypedArray a = context.obtainStyledAttributes(
|
||||
@@ -679,7 +681,15 @@ public class ScrollView extends FrameLayout {
|
||||
* isFinished() is correct.
|
||||
*/
|
||||
mScroller.computeScrollOffset();
|
||||
mIsBeingDragged = !mScroller.isFinished();
|
||||
mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowBottom.isFinished()
|
||||
|| !mEdgeGlowTop.isFinished();
|
||||
// Catch the edge effect if it is active.
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onPullDistance(0f, ev.getX() / getWidth());
|
||||
}
|
||||
if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onPullDistance(0f, 1f - ev.getX() / getWidth());
|
||||
}
|
||||
if (mIsBeingDragged && mScrollStrictSpan == null) {
|
||||
mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
|
||||
}
|
||||
@@ -732,7 +742,8 @@ public class ScrollView extends FrameLayout {
|
||||
if (getChildCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
if ((mIsBeingDragged = !mScroller.isFinished())) {
|
||||
if ((mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowTop.isFinished()
|
||||
|| !mEdgeGlowBottom.isFinished())) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
@@ -793,6 +804,21 @@ public class ScrollView extends FrameLayout {
|
||||
boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
|
||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
|
||||
|
||||
final float displacement = ev.getX(activePointerIndex) / getWidth();
|
||||
if (canOverscroll) {
|
||||
int consumed = 0;
|
||||
if (deltaY < 0 && mEdgeGlowBottom.getDistance() != 0f) {
|
||||
consumed = Math.round(getHeight()
|
||||
* mEdgeGlowBottom.onPullDistance((float) deltaY / getHeight(),
|
||||
1 - displacement));
|
||||
} else if (deltaY > 0 && mEdgeGlowTop.getDistance() != 0f) {
|
||||
consumed = Math.round(-getHeight()
|
||||
* mEdgeGlowTop.onPullDistance((float) -deltaY / getHeight(),
|
||||
displacement));
|
||||
}
|
||||
deltaY -= consumed;
|
||||
}
|
||||
|
||||
// Calling overScrollBy will call onOverScrolled, which
|
||||
// calls onScrollChanged if applicable.
|
||||
if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true)
|
||||
@@ -807,17 +833,17 @@ public class ScrollView extends FrameLayout {
|
||||
mLastMotionY -= mScrollOffset[1];
|
||||
vtev.offsetLocation(0, mScrollOffset[1]);
|
||||
mNestedYOffset += mScrollOffset[1];
|
||||
} else if (canOverscroll) {
|
||||
} else if (canOverscroll && deltaY != 0f) {
|
||||
final int pulledToY = oldY + deltaY;
|
||||
if (pulledToY < 0) {
|
||||
mEdgeGlowTop.onPull((float) deltaY / getHeight(),
|
||||
ev.getX(activePointerIndex) / getWidth());
|
||||
mEdgeGlowTop.onPullDistance((float) -deltaY / getHeight(),
|
||||
displacement);
|
||||
if (!mEdgeGlowBottom.isFinished()) {
|
||||
mEdgeGlowBottom.onRelease();
|
||||
}
|
||||
} else if (pulledToY > range) {
|
||||
mEdgeGlowBottom.onPull((float) deltaY / getHeight(),
|
||||
1.f - ev.getX(activePointerIndex) / getWidth());
|
||||
mEdgeGlowBottom.onPullDistance((float) deltaY / getHeight(),
|
||||
1.f - displacement);
|
||||
if (!mEdgeGlowTop.isFinished()) {
|
||||
mEdgeGlowTop.onRelease();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user