Loading core/java/android/widget/AbsListView.java +85 −3 Original line number Diff line number Diff line Loading @@ -241,6 +241,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te */ public static final int CHOICE_MODE_MULTIPLE_MODAL = 3; /** * When flinging the stretch towards scrolling content, it should destretch quicker than the * fling would normally do. The visual effect of flinging the stretch looks strange as little * appears to happen at first and then when the stretch disappears, the content starts * scrolling quickly. */ private static final float FLING_DESTRETCH_FACTOR = 4f; /** * The thread that created this view. */ Loading Loading @@ -4216,9 +4224,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // fling further. boolean flingVelocity = Math.abs(initialVelocity) > mMinimumVelocity; if (flingVelocity && !mEdgeGlowTop.isFinished()) { if (shouldAbsorb(mEdgeGlowTop, initialVelocity)) { mEdgeGlowTop.onAbsorb(initialVelocity); } else { if (mFlingRunnable == null) { mFlingRunnable = new FlingRunnable(); } mFlingRunnable.start(-initialVelocity); } } else if (flingVelocity && !mEdgeGlowBottom.isFinished()) { if (shouldAbsorb(mEdgeGlowBottom, -initialVelocity)) { mEdgeGlowBottom.onAbsorb(-initialVelocity); } else { if (mFlingRunnable == null) { mFlingRunnable = new FlingRunnable(); } mFlingRunnable.start(-initialVelocity); } } else if (flingVelocity && !((mFirstPosition == 0 && firstChildTop == contentTop - mOverscrollDistance) Loading Loading @@ -4301,6 +4323,60 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } /** * Returns true if edgeEffect should call onAbsorb() with veclocity or false if it should * animate with a fling. It will animate with a fling if the velocity will remove the * EdgeEffect through its normal operation. * * @param edgeEffect The EdgeEffect that might absorb the velocity. * @param velocity The velocity of the fling motion * @return true if the velocity should be absorbed or false if it should be flung. */ private boolean shouldAbsorb(EdgeEffect edgeEffect, int velocity) { if (velocity > 0) { return true; } float distance = edgeEffect.getDistance() * getHeight(); // This is flinging without the spring, so let's see if it will fling past the overscroll if (mFlingRunnable == null) { mFlingRunnable = new FlingRunnable(); } float flingDistance = mFlingRunnable.getSplineFlingDistance(-velocity); return flingDistance < distance; } /** * Used by consumeFlingInHorizontalStretch() and consumeFlinInVerticalStretch() for * consuming deltas from EdgeEffects * @param unconsumed The unconsumed delta that the EdgeEffets may consume * @return The unconsumed delta after the EdgeEffects have had an opportunity to consume. */ private int consumeFlingInStretch(int unconsumed) { if (unconsumed < 0 && mEdgeGlowTop != null && mEdgeGlowTop.getDistance() != 0f) { int size = getHeight(); float deltaDistance = unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(size / FLING_DESTRETCH_FACTOR * mEdgeGlowTop.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowTop.finish(); } return unconsumed - consumed; } if (unconsumed > 0 && mEdgeGlowBottom != null && mEdgeGlowBottom.getDistance() != 0f) { int size = getHeight(); float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(-size / FLING_DESTRETCH_FACTOR * mEdgeGlowBottom.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowBottom.finish(); } return unconsumed - consumed; } return unconsumed; } private boolean shouldDisplayEdgeEffects() { return getOverScrollMode() != OVER_SCROLL_NEVER; } Loading Loading @@ -4783,6 +4859,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mScroller = new OverScroller(getContext()); } float getSplineFlingDistance(int velocity) { return (float) mScroller.getSplineFlingDistance(velocity); } // Use AbsListView#fling(int) instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void start(int initialVelocity) { Loading Loading @@ -4905,6 +4985,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (mItemCount == 0 || getChildCount() == 0) { mEdgeGlowBottom.onRelease(); mEdgeGlowTop.onRelease(); endFling(); return; } Loading @@ -4915,7 +4997,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // Flip sign to convert finger direction to list items direction // (e.g. finger moving down means list is moving towards the top) int delta = mLastFlingY - y; int delta = consumeFlingInStretch(mLastFlingY - y); // Pretend that each frame of a fling scroll is a touch scroll if (delta > 0) { Loading core/java/android/widget/HorizontalScrollView.java +77 −5 Original line number Diff line number Diff line Loading @@ -77,6 +77,14 @@ public class HorizontalScrollView extends FrameLayout { private static final String TAG = "HorizontalScrollView"; /** * When flinging the stretch towards scrolling content, it should destretch quicker than the * fling would normally do. The visual effect of flinging the stretch looks strange as little * appears to happen at first and then when the stretch disappears, the content starts * scrolling quickly. */ private static final float FLING_DESTRETCH_FACTOR = 4f; private long mLastScroll; private final Rect mTempRect = new Rect(); Loading Loading @@ -1456,18 +1464,19 @@ public class HorizontalScrollView extends FrameLayout { int oldY = mScrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); int deltaX = consumeFlingInStretch(x - oldX); if (oldX != x || oldY != y) { if (deltaX != 0 || oldY != y) { final int range = getScrollRange(); final int overscrollMode = getOverScrollMode(); final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0); overScrollBy(x - oldX, y - oldY, oldX, oldY, range, 0, overScrollBy(deltaX, y - oldY, oldX, oldY, range, 0, mOverflingDistance, 0, false); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (canOverscroll) { if (canOverscroll && deltaX != 0) { if (x < 0 && oldX >= 0) { mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity()); } else if (x > range && oldX <= range) { Loading @@ -1482,6 +1491,36 @@ public class HorizontalScrollView extends FrameLayout { } } /** * Used by consumeFlingInHorizontalStretch() and consumeFlinInVerticalStretch() for * consuming deltas from EdgeEffects * @param unconsumed The unconsumed delta that the EdgeEffets may consume * @return The unconsumed delta after the EdgeEffects have had an opportunity to consume. */ private int consumeFlingInStretch(int unconsumed) { if (unconsumed > 0 && mEdgeGlowLeft != null && mEdgeGlowLeft.getDistance() != 0f) { int size = getWidth(); float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(-size / FLING_DESTRETCH_FACTOR * mEdgeGlowLeft.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowLeft.finish(); } return unconsumed - consumed; } if (unconsumed < 0 && mEdgeGlowRight != null && mEdgeGlowRight.getDistance() != 0f) { int size = getWidth(); float deltaDistance = unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(size / FLING_DESTRETCH_FACTOR * mEdgeGlowRight.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowRight.finish(); } return unconsumed - consumed; } return unconsumed; } /** * Scrolls the view to the given child. * Loading Loading @@ -1746,11 +1785,23 @@ public class HorizontalScrollView extends FrameLayout { int maxScroll = Math.max(0, right - width); boolean shouldFling = false; if (mScrollX == 0 && !mEdgeGlowLeft.isFinished()) { if (shouldAbsorb(mEdgeGlowLeft, -velocityX)) { mEdgeGlowLeft.onAbsorb(-velocityX); } else { shouldFling = true; } } else if (mScrollX == maxScroll && !mEdgeGlowRight.isFinished()) { if (shouldAbsorb(mEdgeGlowRight, velocityX)) { mEdgeGlowRight.onAbsorb(velocityX); } else { shouldFling = true; } } else { shouldFling = true; } if (shouldFling) { mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, maxScroll, 0, 0, width / 2, 0); Loading @@ -1773,6 +1824,27 @@ public class HorizontalScrollView extends FrameLayout { } } /** * Returns true if edgeEffect should call onAbsorb() with veclocity or false if it should * animate with a fling. It will animate with a fling if the velocity will remove the * EdgeEffect through its normal operation. * * @param edgeEffect The EdgeEffect that might absorb the velocity. * @param velocity The velocity of the fling motion * @return true if the velocity should be absorbed or false if it should be flung. */ private boolean shouldAbsorb(EdgeEffect edgeEffect, int velocity) { if (velocity > 0) { return true; } float distance = edgeEffect.getDistance() * getWidth(); // This is flinging without the spring, so let's see if it will fling past the overscroll float flingDistance = (float) mScroller.getSplineFlingDistance(-velocity); return flingDistance < distance; } /** * {@inheritDoc} * Loading core/java/android/widget/OverScroller.java +4 −0 Original line number Diff line number Diff line Loading @@ -527,6 +527,10 @@ public class OverScroller { Math.signum(yvel) == Math.signum(dy); } double getSplineFlingDistance(int velocity) { return mScrollerY.getSplineFlingDistance(velocity); } static class SplineOverScroller { // Initial position private int mStart; Loading core/java/android/widget/ScrollView.java +73 −5 Original line number Diff line number Diff line Loading @@ -85,6 +85,14 @@ public class ScrollView extends FrameLayout { private static final String TAG = "ScrollView"; /** * When flinging the stretch towards scrolling content, it should destretch quicker than the * fling would normally do. The visual effect of flinging the stretch looks strange as little * appears to happen at first and then when the stretch disappears, the content starts * scrolling quickly. */ private static final float FLING_DESTRETCH_FACTOR = 4f; @UnsupportedAppUsage private long mLastScroll; Loading Loading @@ -1488,18 +1496,19 @@ public class ScrollView extends FrameLayout { int oldY = mScrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); int deltaY = consumeFlingInStretch(y - oldY); if (oldX != x || oldY != y) { if (oldX != x || deltaY != 0) { final int range = getScrollRange(); final int overscrollMode = getOverScrollMode(); final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0); overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, range, overScrollBy(x - oldX, deltaY, oldX, oldY, 0, range, 0, mOverflingDistance, false); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (canOverscroll) { if (canOverscroll && deltaY != 0) { if (y < 0 && oldY >= 0) { mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity()); } else if (y > range && oldY <= range) { Loading @@ -1520,6 +1529,36 @@ public class ScrollView extends FrameLayout { } } /** * Used by consumeFlingInHorizontalStretch() and consumeFlinInVerticalStretch() for * consuming deltas from EdgeEffects * @param unconsumed The unconsumed delta that the EdgeEffets may consume * @return The unconsumed delta after the EdgeEffects have had an opportunity to consume. */ private int consumeFlingInStretch(int unconsumed) { if (unconsumed > 0 && mEdgeGlowTop != null && mEdgeGlowTop.getDistance() != 0f) { int size = getHeight(); float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(-size / FLING_DESTRETCH_FACTOR * mEdgeGlowTop.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowTop.finish(); } return unconsumed - consumed; } if (unconsumed < 0 && mEdgeGlowBottom != null && mEdgeGlowBottom.getDistance() != 0f) { int size = getHeight(); float deltaDistance = unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(size / FLING_DESTRETCH_FACTOR * mEdgeGlowBottom.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowBottom.finish(); } return unconsumed - consumed; } return unconsumed; } /** * Scrolls the view to the given child. * Loading Loading @@ -1803,14 +1842,43 @@ public class ScrollView extends FrameLayout { fling(velocityY); } else if (!consumed) { if (!mEdgeGlowTop.isFinished()) { if (shouldAbsorb(mEdgeGlowTop, -velocityY)) { mEdgeGlowTop.onAbsorb(-velocityY); } else { fling(velocityY); } } else if (!mEdgeGlowBottom.isFinished()) { if (shouldAbsorb(mEdgeGlowBottom, velocityY)) { mEdgeGlowBottom.onAbsorb(velocityY); } else { fling(velocityY); } } } } } /** * Returns true if edgeEffect should call onAbsorb() with veclocity or false if it should * animate with a fling. It will animate with a fling if the velocity will remove the * EdgeEffect through its normal operation. * * @param edgeEffect The EdgeEffect that might absorb the velocity. * @param velocity The velocity of the fling motion * @return true if the velocity should be absorbed or false if it should be flung. */ private boolean shouldAbsorb(EdgeEffect edgeEffect, int velocity) { if (velocity > 0) { return true; } float distance = edgeEffect.getDistance() * getHeight(); // This is flinging without the spring, so let's see if it will fling past the overscroll float flingDistance = (float) mScroller.getSplineFlingDistance(-velocity); return flingDistance < distance; } @UnsupportedAppUsage private void endDrag() { mIsBeingDragged = false; Loading Loading
core/java/android/widget/AbsListView.java +85 −3 Original line number Diff line number Diff line Loading @@ -241,6 +241,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te */ public static final int CHOICE_MODE_MULTIPLE_MODAL = 3; /** * When flinging the stretch towards scrolling content, it should destretch quicker than the * fling would normally do. The visual effect of flinging the stretch looks strange as little * appears to happen at first and then when the stretch disappears, the content starts * scrolling quickly. */ private static final float FLING_DESTRETCH_FACTOR = 4f; /** * The thread that created this view. */ Loading Loading @@ -4216,9 +4224,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // fling further. boolean flingVelocity = Math.abs(initialVelocity) > mMinimumVelocity; if (flingVelocity && !mEdgeGlowTop.isFinished()) { if (shouldAbsorb(mEdgeGlowTop, initialVelocity)) { mEdgeGlowTop.onAbsorb(initialVelocity); } else { if (mFlingRunnable == null) { mFlingRunnable = new FlingRunnable(); } mFlingRunnable.start(-initialVelocity); } } else if (flingVelocity && !mEdgeGlowBottom.isFinished()) { if (shouldAbsorb(mEdgeGlowBottom, -initialVelocity)) { mEdgeGlowBottom.onAbsorb(-initialVelocity); } else { if (mFlingRunnable == null) { mFlingRunnable = new FlingRunnable(); } mFlingRunnable.start(-initialVelocity); } } else if (flingVelocity && !((mFirstPosition == 0 && firstChildTop == contentTop - mOverscrollDistance) Loading Loading @@ -4301,6 +4323,60 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } /** * Returns true if edgeEffect should call onAbsorb() with veclocity or false if it should * animate with a fling. It will animate with a fling if the velocity will remove the * EdgeEffect through its normal operation. * * @param edgeEffect The EdgeEffect that might absorb the velocity. * @param velocity The velocity of the fling motion * @return true if the velocity should be absorbed or false if it should be flung. */ private boolean shouldAbsorb(EdgeEffect edgeEffect, int velocity) { if (velocity > 0) { return true; } float distance = edgeEffect.getDistance() * getHeight(); // This is flinging without the spring, so let's see if it will fling past the overscroll if (mFlingRunnable == null) { mFlingRunnable = new FlingRunnable(); } float flingDistance = mFlingRunnable.getSplineFlingDistance(-velocity); return flingDistance < distance; } /** * Used by consumeFlingInHorizontalStretch() and consumeFlinInVerticalStretch() for * consuming deltas from EdgeEffects * @param unconsumed The unconsumed delta that the EdgeEffets may consume * @return The unconsumed delta after the EdgeEffects have had an opportunity to consume. */ private int consumeFlingInStretch(int unconsumed) { if (unconsumed < 0 && mEdgeGlowTop != null && mEdgeGlowTop.getDistance() != 0f) { int size = getHeight(); float deltaDistance = unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(size / FLING_DESTRETCH_FACTOR * mEdgeGlowTop.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowTop.finish(); } return unconsumed - consumed; } if (unconsumed > 0 && mEdgeGlowBottom != null && mEdgeGlowBottom.getDistance() != 0f) { int size = getHeight(); float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(-size / FLING_DESTRETCH_FACTOR * mEdgeGlowBottom.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowBottom.finish(); } return unconsumed - consumed; } return unconsumed; } private boolean shouldDisplayEdgeEffects() { return getOverScrollMode() != OVER_SCROLL_NEVER; } Loading Loading @@ -4783,6 +4859,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mScroller = new OverScroller(getContext()); } float getSplineFlingDistance(int velocity) { return (float) mScroller.getSplineFlingDistance(velocity); } // Use AbsListView#fling(int) instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void start(int initialVelocity) { Loading Loading @@ -4905,6 +4985,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (mItemCount == 0 || getChildCount() == 0) { mEdgeGlowBottom.onRelease(); mEdgeGlowTop.onRelease(); endFling(); return; } Loading @@ -4915,7 +4997,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // Flip sign to convert finger direction to list items direction // (e.g. finger moving down means list is moving towards the top) int delta = mLastFlingY - y; int delta = consumeFlingInStretch(mLastFlingY - y); // Pretend that each frame of a fling scroll is a touch scroll if (delta > 0) { Loading
core/java/android/widget/HorizontalScrollView.java +77 −5 Original line number Diff line number Diff line Loading @@ -77,6 +77,14 @@ public class HorizontalScrollView extends FrameLayout { private static final String TAG = "HorizontalScrollView"; /** * When flinging the stretch towards scrolling content, it should destretch quicker than the * fling would normally do. The visual effect of flinging the stretch looks strange as little * appears to happen at first and then when the stretch disappears, the content starts * scrolling quickly. */ private static final float FLING_DESTRETCH_FACTOR = 4f; private long mLastScroll; private final Rect mTempRect = new Rect(); Loading Loading @@ -1456,18 +1464,19 @@ public class HorizontalScrollView extends FrameLayout { int oldY = mScrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); int deltaX = consumeFlingInStretch(x - oldX); if (oldX != x || oldY != y) { if (deltaX != 0 || oldY != y) { final int range = getScrollRange(); final int overscrollMode = getOverScrollMode(); final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0); overScrollBy(x - oldX, y - oldY, oldX, oldY, range, 0, overScrollBy(deltaX, y - oldY, oldX, oldY, range, 0, mOverflingDistance, 0, false); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (canOverscroll) { if (canOverscroll && deltaX != 0) { if (x < 0 && oldX >= 0) { mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity()); } else if (x > range && oldX <= range) { Loading @@ -1482,6 +1491,36 @@ public class HorizontalScrollView extends FrameLayout { } } /** * Used by consumeFlingInHorizontalStretch() and consumeFlinInVerticalStretch() for * consuming deltas from EdgeEffects * @param unconsumed The unconsumed delta that the EdgeEffets may consume * @return The unconsumed delta after the EdgeEffects have had an opportunity to consume. */ private int consumeFlingInStretch(int unconsumed) { if (unconsumed > 0 && mEdgeGlowLeft != null && mEdgeGlowLeft.getDistance() != 0f) { int size = getWidth(); float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(-size / FLING_DESTRETCH_FACTOR * mEdgeGlowLeft.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowLeft.finish(); } return unconsumed - consumed; } if (unconsumed < 0 && mEdgeGlowRight != null && mEdgeGlowRight.getDistance() != 0f) { int size = getWidth(); float deltaDistance = unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(size / FLING_DESTRETCH_FACTOR * mEdgeGlowRight.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowRight.finish(); } return unconsumed - consumed; } return unconsumed; } /** * Scrolls the view to the given child. * Loading Loading @@ -1746,11 +1785,23 @@ public class HorizontalScrollView extends FrameLayout { int maxScroll = Math.max(0, right - width); boolean shouldFling = false; if (mScrollX == 0 && !mEdgeGlowLeft.isFinished()) { if (shouldAbsorb(mEdgeGlowLeft, -velocityX)) { mEdgeGlowLeft.onAbsorb(-velocityX); } else { shouldFling = true; } } else if (mScrollX == maxScroll && !mEdgeGlowRight.isFinished()) { if (shouldAbsorb(mEdgeGlowRight, velocityX)) { mEdgeGlowRight.onAbsorb(velocityX); } else { shouldFling = true; } } else { shouldFling = true; } if (shouldFling) { mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, maxScroll, 0, 0, width / 2, 0); Loading @@ -1773,6 +1824,27 @@ public class HorizontalScrollView extends FrameLayout { } } /** * Returns true if edgeEffect should call onAbsorb() with veclocity or false if it should * animate with a fling. It will animate with a fling if the velocity will remove the * EdgeEffect through its normal operation. * * @param edgeEffect The EdgeEffect that might absorb the velocity. * @param velocity The velocity of the fling motion * @return true if the velocity should be absorbed or false if it should be flung. */ private boolean shouldAbsorb(EdgeEffect edgeEffect, int velocity) { if (velocity > 0) { return true; } float distance = edgeEffect.getDistance() * getWidth(); // This is flinging without the spring, so let's see if it will fling past the overscroll float flingDistance = (float) mScroller.getSplineFlingDistance(-velocity); return flingDistance < distance; } /** * {@inheritDoc} * Loading
core/java/android/widget/OverScroller.java +4 −0 Original line number Diff line number Diff line Loading @@ -527,6 +527,10 @@ public class OverScroller { Math.signum(yvel) == Math.signum(dy); } double getSplineFlingDistance(int velocity) { return mScrollerY.getSplineFlingDistance(velocity); } static class SplineOverScroller { // Initial position private int mStart; Loading
core/java/android/widget/ScrollView.java +73 −5 Original line number Diff line number Diff line Loading @@ -85,6 +85,14 @@ public class ScrollView extends FrameLayout { private static final String TAG = "ScrollView"; /** * When flinging the stretch towards scrolling content, it should destretch quicker than the * fling would normally do. The visual effect of flinging the stretch looks strange as little * appears to happen at first and then when the stretch disappears, the content starts * scrolling quickly. */ private static final float FLING_DESTRETCH_FACTOR = 4f; @UnsupportedAppUsage private long mLastScroll; Loading Loading @@ -1488,18 +1496,19 @@ public class ScrollView extends FrameLayout { int oldY = mScrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); int deltaY = consumeFlingInStretch(y - oldY); if (oldX != x || oldY != y) { if (oldX != x || deltaY != 0) { final int range = getScrollRange(); final int overscrollMode = getOverScrollMode(); final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0); overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, range, overScrollBy(x - oldX, deltaY, oldX, oldY, 0, range, 0, mOverflingDistance, false); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (canOverscroll) { if (canOverscroll && deltaY != 0) { if (y < 0 && oldY >= 0) { mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity()); } else if (y > range && oldY <= range) { Loading @@ -1520,6 +1529,36 @@ public class ScrollView extends FrameLayout { } } /** * Used by consumeFlingInHorizontalStretch() and consumeFlinInVerticalStretch() for * consuming deltas from EdgeEffects * @param unconsumed The unconsumed delta that the EdgeEffets may consume * @return The unconsumed delta after the EdgeEffects have had an opportunity to consume. */ private int consumeFlingInStretch(int unconsumed) { if (unconsumed > 0 && mEdgeGlowTop != null && mEdgeGlowTop.getDistance() != 0f) { int size = getHeight(); float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(-size / FLING_DESTRETCH_FACTOR * mEdgeGlowTop.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowTop.finish(); } return unconsumed - consumed; } if (unconsumed < 0 && mEdgeGlowBottom != null && mEdgeGlowBottom.getDistance() != 0f) { int size = getHeight(); float deltaDistance = unconsumed * FLING_DESTRETCH_FACTOR / size; int consumed = Math.round(size / FLING_DESTRETCH_FACTOR * mEdgeGlowBottom.onPullDistance(deltaDistance, 0.5f)); if (consumed != unconsumed) { mEdgeGlowBottom.finish(); } return unconsumed - consumed; } return unconsumed; } /** * Scrolls the view to the given child. * Loading Loading @@ -1803,14 +1842,43 @@ public class ScrollView extends FrameLayout { fling(velocityY); } else if (!consumed) { if (!mEdgeGlowTop.isFinished()) { if (shouldAbsorb(mEdgeGlowTop, -velocityY)) { mEdgeGlowTop.onAbsorb(-velocityY); } else { fling(velocityY); } } else if (!mEdgeGlowBottom.isFinished()) { if (shouldAbsorb(mEdgeGlowBottom, velocityY)) { mEdgeGlowBottom.onAbsorb(velocityY); } else { fling(velocityY); } } } } } /** * Returns true if edgeEffect should call onAbsorb() with veclocity or false if it should * animate with a fling. It will animate with a fling if the velocity will remove the * EdgeEffect through its normal operation. * * @param edgeEffect The EdgeEffect that might absorb the velocity. * @param velocity The velocity of the fling motion * @return true if the velocity should be absorbed or false if it should be flung. */ private boolean shouldAbsorb(EdgeEffect edgeEffect, int velocity) { if (velocity > 0) { return true; } float distance = edgeEffect.getDistance() * getHeight(); // This is flinging without the spring, so let's see if it will fling past the overscroll float flingDistance = (float) mScroller.getSplineFlingDistance(-velocity); return flingDistance < distance; } @UnsupportedAppUsage private void endDrag() { mIsBeingDragged = false; Loading