Loading core/java/android/widget/HorizontalScrollView.java +19 −33 Original line number Diff line number Diff line Loading @@ -63,7 +63,7 @@ public class HorizontalScrollView extends FrameLayout { private long mLastScroll; private final Rect mTempRect = new Rect(); private Scroller mScroller; private OverScroller mScroller; /** * Flag to indicate that we are moving focus ourselves. This is so the Loading Loading @@ -177,7 +177,7 @@ public class HorizontalScrollView extends FrameLayout { private void initScrollView() { mScroller = new Scroller(getContext()); mScroller = new OverScroller(getContext()); setFocusable(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setWillNotDraw(false); Loading Loading @@ -380,11 +380,6 @@ public class HorizontalScrollView extends FrameLayout { return true; } if (!canScroll()) { mIsBeingDragged = false; return false; } final float x = ev.getX(); switch (action) { Loading Loading @@ -440,10 +435,6 @@ public class HorizontalScrollView extends FrameLayout { return false; } if (!canScroll()) { return false; } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } Loading @@ -470,25 +461,23 @@ public class HorizontalScrollView extends FrameLayout { final int deltaX = (int) (mLastMotionX - x); mLastMotionX = x; if (deltaX < 0) { if (mScrollX > 0) { scrollBy(deltaX, 0); } } else if (deltaX > 0) { final int rightEdge = getWidth() - mPaddingRight; final int availableToScroll = getChildAt(0).getRight() - mScrollX - rightEdge; if (availableToScroll > 0) { scrollBy(Math.min(availableToScroll, deltaX), 0); } } super.scrollTo(mScrollX + deltaX, mScrollY); break; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) velocityTracker.getXVelocity(); if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) { if (getChildCount() > 0) { if ((Math.abs(initialVelocity) > mMinimumVelocity)) { fling(-initialVelocity); } else { final int right = Math.max(0, getChildAt(0).getHeight() - (getHeight() - mPaddingRight - mPaddingLeft)); if (mScroller.springback(mScrollX, mScrollY, 0, 0, right, 0)) { invalidate(); } } } if (mVelocityTracker != null) { Loading Loading @@ -913,14 +902,10 @@ public class HorizontalScrollView extends FrameLayout { int oldY = mScrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); if (getChildCount() > 0) { View child = getChildAt(0); mScrollX = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth()); mScrollY = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight()); } else { mScrollX = x; mScrollY = y; } if (oldX != mScrollX || oldY != mScrollY) { onScrollChanged(mScrollX, mScrollY, oldX, oldY); } Loading Loading @@ -1156,7 +1141,8 @@ public class HorizontalScrollView extends FrameLayout { int width = getWidth() - mPaddingRight - mPaddingLeft; int right = getChildAt(0).getWidth(); mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, right - width, 0, 0); mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, Math.max(0, right - width), 0, 0, width/2, 0); final boolean movingRight = velocityX > 0; Loading core/java/android/widget/OverScroller.java 0 → 100644 +354 −0 Original line number Diff line number Diff line /* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.widget; import android.content.Context; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.DecelerateInterpolator; /** * This class encapsulates scrolling with the ability to overshoot the bounds * of a scrolling operation. This class attempts to be a drop-in replacement * for {@link android.widget.Scroller} in most cases. * * @hide Pending API approval */ public class OverScroller { private static final int SPRINGBACK_DURATION = 150; private static final int OVERFLING_DURATION = 150; private static final int MODE_DEFAULT = 0; private static final int MODE_OVERFLING = 1; private static final int MODE_SPRINGBACK = 2; private Scroller mDefaultScroller; private Scroller mDecelScroller; private Scroller mAccelDecelScroller; private Scroller mCurrScroller; private int mScrollMode = MODE_DEFAULT; private int mMinimumX; private int mMinimumY; private int mMaximumX; private int mMaximumY; public OverScroller(Context context) { mDefaultScroller = new Scroller(context); mDecelScroller = new Scroller(context, new DecelerateInterpolator(3.f)); mAccelDecelScroller = new Scroller(context, new AccelerateDecelerateInterpolator()); mCurrScroller = mDefaultScroller; } /** * Call this when you want to know the new location. If it returns true, * the animation is not yet finished. loc will be altered to provide the * new location. */ public boolean computeScrollOffset() { boolean inProgress = mCurrScroller.computeScrollOffset(); switch (mScrollMode) { case MODE_OVERFLING: if (!inProgress) { // Overfling ended if (springback(mCurrScroller.getCurrX(), mCurrScroller.getCurrY(), mMinimumX, mMaximumX, mMinimumY, mMaximumY, mAccelDecelScroller)) { return mCurrScroller.computeScrollOffset(); } else { mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; } } break; case MODE_SPRINGBACK: if (!inProgress) { mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; } break; case MODE_DEFAULT: // Fling/autoscroll - did we go off the edge? if (inProgress) { Scroller scroller = mCurrScroller; final int x = scroller.getCurrX(); final int y = scroller.getCurrY(); final int minX = mMinimumX; final int maxX = mMaximumX; final int minY = mMinimumY; final int maxY = mMaximumY; if (x < minX || x > maxX || y < minY || y > maxY) { final int startx = scroller.getStartX(); final int starty = scroller.getStartY(); final int time = scroller.timePassed(); final float timeSecs = time / 1000.f; final float xvel = ((x - startx) / timeSecs); final float yvel = ((y - starty) / timeSecs); if ((x < minX && xvel > 0) || (y < minY && yvel > 0) || (x > maxX && xvel < 0) || (y > maxY && yvel < 0)) { // If our velocity would take us back into valid areas, // try to springback rather than overfling. if (springback(x, y, minX, maxX, minY, maxY)) { return mCurrScroller.computeScrollOffset(); } } else { overfling(x, y, xvel, yvel); return mCurrScroller.computeScrollOffset(); } } } break; } return inProgress; } private void overfling(int startx, int starty, float xvel, float yvel) { Scroller scroller = mDecelScroller; final float durationSecs = (OVERFLING_DURATION / 1000.f); int dx = (int)(xvel * durationSecs) / 8; int dy = (int)(yvel * durationSecs) / 8; scroller.startScroll(startx, starty, dx, dy, OVERFLING_DURATION); mCurrScroller.abortAnimation(); mCurrScroller = scroller; mScrollMode = MODE_OVERFLING; } /** * Call this when you want to 'spring back' into a valid coordinate range. * * @param startX Starting X coordinate * @param startY Starting Y coordinate * @param minX Minimum valid X value * @param maxX Maximum valid X value * @param minY Minimum valid Y value * @param maxY Minimum valid Y value * @return true if a springback was initiated, false if startX/startY was * already within the valid range. */ public boolean springback(int startX, int startY, int minX, int maxX, int minY, int maxY) { return springback(startX, startY, minX, maxX, minY, maxY, mDecelScroller); } private boolean springback(int startX, int startY, int minX, int maxX, int minY, int maxY, Scroller scroller) { int xoff = 0; int yoff = 0; if (startX < minX) { xoff = minX - startX; } else if (startX > maxX) { xoff = maxX - startX; } if (startY < minY) { yoff = minY - startY; } else if (startY > maxY) { yoff = maxY - startY; } if (xoff != 0 || yoff != 0) { scroller.startScroll(startX, startY, xoff, yoff, SPRINGBACK_DURATION); mCurrScroller.abortAnimation(); mCurrScroller = scroller; mScrollMode = MODE_SPRINGBACK; return true; } return false; } /** * * Returns whether the scroller has finished scrolling. * * @return True if the scroller has finished scrolling, false otherwise. */ public final boolean isFinished() { return mCurrScroller.isFinished(); } /** * Returns the current X offset in the scroll. * * @return The new X offset as an absolute distance from the origin. */ public final int getCurrX() { return mCurrScroller.getCurrX(); } /** * Returns the current Y offset in the scroll. * * @return The new Y offset as an absolute distance from the origin. */ public final int getCurrY() { return mCurrScroller.getCurrY(); } /** * Stops the animation, resets any springback/overfling and completes * any standard flings/scrolls in progress. */ public void abortAnimation() { mCurrScroller.abortAnimation(); mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; mCurrScroller.abortAnimation(); } /** * Start scrolling by providing a starting point and the distance to travel. * The scroll will use the default value of 250 milliseconds for the * duration. * * @param startX Starting horizontal scroll offset in pixels. Positive * numbers will scroll the content to the left. * @param startY Starting vertical scroll offset in pixels. Positive numbers * will scroll the content up. * @param dx Horizontal distance to travel. Positive numbers will scroll the * content to the left. * @param dy Vertical distance to travel. Positive numbers will scroll the * content up. */ public void startScroll(int startX, int startY, int dx, int dy) { mCurrScroller.abortAnimation(); mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; mMinimumX = Math.min(startX, startX + dx); mMinimumY = Math.min(startY, startY + dy); mMaximumX = Math.max(startX, startX + dx); mMaximumY = Math.max(startY, startY + dy); mCurrScroller.startScroll(startX, startY, dx, dy); } /** * Start scrolling by providing a starting point and the distance to travel. * * @param startX Starting horizontal scroll offset in pixels. Positive * numbers will scroll the content to the left. * @param startY Starting vertical scroll offset in pixels. Positive numbers * will scroll the content up. * @param dx Horizontal distance to travel. Positive numbers will scroll the * content to the left. * @param dy Vertical distance to travel. Positive numbers will scroll the * content up. * @param duration Duration of the scroll in milliseconds. */ public void startScroll(int startX, int startY, int dx, int dy, int duration) { mCurrScroller.abortAnimation(); mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; mMinimumX = Math.min(startX, startX + dx); mMinimumY = Math.min(startY, startY + dy); mMaximumX = Math.max(startX, startX + dx); mMaximumY = Math.max(startY, startY + dy); mCurrScroller.startScroll(startX, startY, dx, dy, duration); } /** * Returns the duration of the active scroll in progress; standard, fling, * springback, or overfling. Does not account for any overflings or springback * that may result. */ public int getDuration() { return mCurrScroller.getDuration(); } /** * Start scrolling based on a fling gesture. The distance travelled will * depend on the initial velocity of the fling. * * @param startX Starting point of the scroll (X) * @param startY Starting point of the scroll (Y) * @param velocityX Initial velocity of the fling (X) measured in pixels per * second. * @param velocityY Initial velocity of the fling (Y) measured in pixels per * second * @param minX Minimum X value. The scroller will not scroll past this * point. * @param maxX Maximum X value. The scroller will not scroll past this * point. * @param minY Minimum Y value. The scroller will not scroll past this * point. * @param maxY Maximum Y value. The scroller will not scroll past this * point. */ public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) { this.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0); } /** * Start scrolling based on a fling gesture. The distance travelled will * depend on the initial velocity of the fling. * * @param startX Starting point of the scroll (X) * @param startY Starting point of the scroll (Y) * @param velocityX Initial velocity of the fling (X) measured in pixels per * second. * @param velocityY Initial velocity of the fling (Y) measured in pixels per * second * @param minX Minimum X value. The scroller will not scroll past this * point unless overX > 0. If overfling is allowed, it will use minX * as a springback boundary. * @param maxX Maximum X value. The scroller will not scroll past this * point unless overX > 0. If overfling is allowed, it will use maxX * as a springback boundary. * @param minY Minimum Y value. The scroller will not scroll past this * point unless overY > 0. If overfling is allowed, it will use minY * as a springback boundary. * @param maxY Maximum Y value. The scroller will not scroll past this * point unless overY > 0. If overfling is allowed, it will use maxY * as a springback boundary. * @param overX Overfling range. If > 0, horizontal overfling in either * direction will be possible. * @param overY Overfling range. If > 0, vertical overfling in either * direction will be possible. */ public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, int overX, int overY) { mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; mMinimumX = minX; mMaximumX = maxX; mMinimumY = minY; mMaximumY = maxY; mCurrScroller.fling(startX, startY, velocityX, velocityY, minX - overX, maxX + overX, minY - overY, maxY + overY); } /** * Returns where the scroll will end. Valid only for "fling" scrolls. * * @return The final X offset as an absolute distance from the origin. */ public int getFinalX() { return mCurrScroller.getFinalX(); } /** * Returns where the scroll will end. Valid only for "fling" scrolls. * * @return The final Y offset as an absolute distance from the origin. */ public int getFinalY() { return mCurrScroller.getFinalY(); } } core/java/android/widget/ScrollView.java +21 −35 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.widget; import com.android.internal.R; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; Loading @@ -30,8 +32,6 @@ import android.view.ViewGroup; import android.view.ViewParent; import android.view.animation.AnimationUtils; import com.android.internal.R; import java.util.List; /** Loading Loading @@ -59,7 +59,7 @@ public class ScrollView extends FrameLayout { private long mLastScroll; private final Rect mTempRect = new Rect(); private Scroller mScroller; private OverScroller mScroller; /** * Flag to indicate that we are moving focus ourselves. This is so the Loading Loading @@ -173,7 +173,7 @@ public class ScrollView extends FrameLayout { private void initScrollView() { mScroller = new Scroller(getContext()); mScroller = new OverScroller(getContext()); setFocusable(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setWillNotDraw(false); Loading Loading @@ -378,11 +378,6 @@ public class ScrollView extends FrameLayout { return true; } if (!canScroll()) { mIsBeingDragged = false; return false; } final float y = ev.getY(); switch (action) { Loading Loading @@ -438,10 +433,6 @@ public class ScrollView extends FrameLayout { return false; } if (!canScroll()) { return false; } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } Loading @@ -468,25 +459,23 @@ public class ScrollView extends FrameLayout { final int deltaY = (int) (mLastMotionY - y); mLastMotionY = y; if (deltaY < 0) { if (mScrollY > 0) { scrollBy(0, deltaY); } } else if (deltaY > 0) { final int bottomEdge = getHeight() - mPaddingBottom; final int availableToScroll = getChildAt(0).getBottom() - mScrollY - bottomEdge; if (availableToScroll > 0) { scrollBy(0, Math.min(availableToScroll, deltaY)); } } super.scrollTo(mScrollX, mScrollY + deltaY); break; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) velocityTracker.getYVelocity(); if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) { if (getChildCount() > 0) { if ((Math.abs(initialVelocity) > mMinimumVelocity)) { fling(-initialVelocity); } else { final int bottom = Math.max(0, getChildAt(0).getHeight() - (getHeight() - mPaddingBottom - mPaddingTop)); if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, bottom)) { invalidate(); } } } if (mVelocityTracker != null) { Loading Loading @@ -915,14 +904,10 @@ public class ScrollView extends FrameLayout { int oldY = mScrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); if (getChildCount() > 0) { View child = getChildAt(0); mScrollX = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth()); mScrollY = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight()); } else { mScrollX = x; mScrollY = y; } if (oldX != mScrollX || oldY != mScrollY) { onScrollChanged(mScrollX, mScrollY, oldX, oldY); } Loading Loading @@ -1159,7 +1144,8 @@ public class ScrollView extends FrameLayout { int height = getHeight() - mPaddingBottom - mPaddingTop; int bottom = getChildAt(0).getHeight(); mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0, bottom - height); mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0, Math.max(0, bottom - height), 0, height/2); final boolean movingDown = velocityY > 0; Loading Loading
core/java/android/widget/HorizontalScrollView.java +19 −33 Original line number Diff line number Diff line Loading @@ -63,7 +63,7 @@ public class HorizontalScrollView extends FrameLayout { private long mLastScroll; private final Rect mTempRect = new Rect(); private Scroller mScroller; private OverScroller mScroller; /** * Flag to indicate that we are moving focus ourselves. This is so the Loading Loading @@ -177,7 +177,7 @@ public class HorizontalScrollView extends FrameLayout { private void initScrollView() { mScroller = new Scroller(getContext()); mScroller = new OverScroller(getContext()); setFocusable(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setWillNotDraw(false); Loading Loading @@ -380,11 +380,6 @@ public class HorizontalScrollView extends FrameLayout { return true; } if (!canScroll()) { mIsBeingDragged = false; return false; } final float x = ev.getX(); switch (action) { Loading Loading @@ -440,10 +435,6 @@ public class HorizontalScrollView extends FrameLayout { return false; } if (!canScroll()) { return false; } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } Loading @@ -470,25 +461,23 @@ public class HorizontalScrollView extends FrameLayout { final int deltaX = (int) (mLastMotionX - x); mLastMotionX = x; if (deltaX < 0) { if (mScrollX > 0) { scrollBy(deltaX, 0); } } else if (deltaX > 0) { final int rightEdge = getWidth() - mPaddingRight; final int availableToScroll = getChildAt(0).getRight() - mScrollX - rightEdge; if (availableToScroll > 0) { scrollBy(Math.min(availableToScroll, deltaX), 0); } } super.scrollTo(mScrollX + deltaX, mScrollY); break; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) velocityTracker.getXVelocity(); if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) { if (getChildCount() > 0) { if ((Math.abs(initialVelocity) > mMinimumVelocity)) { fling(-initialVelocity); } else { final int right = Math.max(0, getChildAt(0).getHeight() - (getHeight() - mPaddingRight - mPaddingLeft)); if (mScroller.springback(mScrollX, mScrollY, 0, 0, right, 0)) { invalidate(); } } } if (mVelocityTracker != null) { Loading Loading @@ -913,14 +902,10 @@ public class HorizontalScrollView extends FrameLayout { int oldY = mScrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); if (getChildCount() > 0) { View child = getChildAt(0); mScrollX = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth()); mScrollY = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight()); } else { mScrollX = x; mScrollY = y; } if (oldX != mScrollX || oldY != mScrollY) { onScrollChanged(mScrollX, mScrollY, oldX, oldY); } Loading Loading @@ -1156,7 +1141,8 @@ public class HorizontalScrollView extends FrameLayout { int width = getWidth() - mPaddingRight - mPaddingLeft; int right = getChildAt(0).getWidth(); mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, right - width, 0, 0); mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, Math.max(0, right - width), 0, 0, width/2, 0); final boolean movingRight = velocityX > 0; Loading
core/java/android/widget/OverScroller.java 0 → 100644 +354 −0 Original line number Diff line number Diff line /* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.widget; import android.content.Context; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.DecelerateInterpolator; /** * This class encapsulates scrolling with the ability to overshoot the bounds * of a scrolling operation. This class attempts to be a drop-in replacement * for {@link android.widget.Scroller} in most cases. * * @hide Pending API approval */ public class OverScroller { private static final int SPRINGBACK_DURATION = 150; private static final int OVERFLING_DURATION = 150; private static final int MODE_DEFAULT = 0; private static final int MODE_OVERFLING = 1; private static final int MODE_SPRINGBACK = 2; private Scroller mDefaultScroller; private Scroller mDecelScroller; private Scroller mAccelDecelScroller; private Scroller mCurrScroller; private int mScrollMode = MODE_DEFAULT; private int mMinimumX; private int mMinimumY; private int mMaximumX; private int mMaximumY; public OverScroller(Context context) { mDefaultScroller = new Scroller(context); mDecelScroller = new Scroller(context, new DecelerateInterpolator(3.f)); mAccelDecelScroller = new Scroller(context, new AccelerateDecelerateInterpolator()); mCurrScroller = mDefaultScroller; } /** * Call this when you want to know the new location. If it returns true, * the animation is not yet finished. loc will be altered to provide the * new location. */ public boolean computeScrollOffset() { boolean inProgress = mCurrScroller.computeScrollOffset(); switch (mScrollMode) { case MODE_OVERFLING: if (!inProgress) { // Overfling ended if (springback(mCurrScroller.getCurrX(), mCurrScroller.getCurrY(), mMinimumX, mMaximumX, mMinimumY, mMaximumY, mAccelDecelScroller)) { return mCurrScroller.computeScrollOffset(); } else { mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; } } break; case MODE_SPRINGBACK: if (!inProgress) { mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; } break; case MODE_DEFAULT: // Fling/autoscroll - did we go off the edge? if (inProgress) { Scroller scroller = mCurrScroller; final int x = scroller.getCurrX(); final int y = scroller.getCurrY(); final int minX = mMinimumX; final int maxX = mMaximumX; final int minY = mMinimumY; final int maxY = mMaximumY; if (x < minX || x > maxX || y < minY || y > maxY) { final int startx = scroller.getStartX(); final int starty = scroller.getStartY(); final int time = scroller.timePassed(); final float timeSecs = time / 1000.f; final float xvel = ((x - startx) / timeSecs); final float yvel = ((y - starty) / timeSecs); if ((x < minX && xvel > 0) || (y < minY && yvel > 0) || (x > maxX && xvel < 0) || (y > maxY && yvel < 0)) { // If our velocity would take us back into valid areas, // try to springback rather than overfling. if (springback(x, y, minX, maxX, minY, maxY)) { return mCurrScroller.computeScrollOffset(); } } else { overfling(x, y, xvel, yvel); return mCurrScroller.computeScrollOffset(); } } } break; } return inProgress; } private void overfling(int startx, int starty, float xvel, float yvel) { Scroller scroller = mDecelScroller; final float durationSecs = (OVERFLING_DURATION / 1000.f); int dx = (int)(xvel * durationSecs) / 8; int dy = (int)(yvel * durationSecs) / 8; scroller.startScroll(startx, starty, dx, dy, OVERFLING_DURATION); mCurrScroller.abortAnimation(); mCurrScroller = scroller; mScrollMode = MODE_OVERFLING; } /** * Call this when you want to 'spring back' into a valid coordinate range. * * @param startX Starting X coordinate * @param startY Starting Y coordinate * @param minX Minimum valid X value * @param maxX Maximum valid X value * @param minY Minimum valid Y value * @param maxY Minimum valid Y value * @return true if a springback was initiated, false if startX/startY was * already within the valid range. */ public boolean springback(int startX, int startY, int minX, int maxX, int minY, int maxY) { return springback(startX, startY, minX, maxX, minY, maxY, mDecelScroller); } private boolean springback(int startX, int startY, int minX, int maxX, int minY, int maxY, Scroller scroller) { int xoff = 0; int yoff = 0; if (startX < minX) { xoff = minX - startX; } else if (startX > maxX) { xoff = maxX - startX; } if (startY < minY) { yoff = minY - startY; } else if (startY > maxY) { yoff = maxY - startY; } if (xoff != 0 || yoff != 0) { scroller.startScroll(startX, startY, xoff, yoff, SPRINGBACK_DURATION); mCurrScroller.abortAnimation(); mCurrScroller = scroller; mScrollMode = MODE_SPRINGBACK; return true; } return false; } /** * * Returns whether the scroller has finished scrolling. * * @return True if the scroller has finished scrolling, false otherwise. */ public final boolean isFinished() { return mCurrScroller.isFinished(); } /** * Returns the current X offset in the scroll. * * @return The new X offset as an absolute distance from the origin. */ public final int getCurrX() { return mCurrScroller.getCurrX(); } /** * Returns the current Y offset in the scroll. * * @return The new Y offset as an absolute distance from the origin. */ public final int getCurrY() { return mCurrScroller.getCurrY(); } /** * Stops the animation, resets any springback/overfling and completes * any standard flings/scrolls in progress. */ public void abortAnimation() { mCurrScroller.abortAnimation(); mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; mCurrScroller.abortAnimation(); } /** * Start scrolling by providing a starting point and the distance to travel. * The scroll will use the default value of 250 milliseconds for the * duration. * * @param startX Starting horizontal scroll offset in pixels. Positive * numbers will scroll the content to the left. * @param startY Starting vertical scroll offset in pixels. Positive numbers * will scroll the content up. * @param dx Horizontal distance to travel. Positive numbers will scroll the * content to the left. * @param dy Vertical distance to travel. Positive numbers will scroll the * content up. */ public void startScroll(int startX, int startY, int dx, int dy) { mCurrScroller.abortAnimation(); mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; mMinimumX = Math.min(startX, startX + dx); mMinimumY = Math.min(startY, startY + dy); mMaximumX = Math.max(startX, startX + dx); mMaximumY = Math.max(startY, startY + dy); mCurrScroller.startScroll(startX, startY, dx, dy); } /** * Start scrolling by providing a starting point and the distance to travel. * * @param startX Starting horizontal scroll offset in pixels. Positive * numbers will scroll the content to the left. * @param startY Starting vertical scroll offset in pixels. Positive numbers * will scroll the content up. * @param dx Horizontal distance to travel. Positive numbers will scroll the * content to the left. * @param dy Vertical distance to travel. Positive numbers will scroll the * content up. * @param duration Duration of the scroll in milliseconds. */ public void startScroll(int startX, int startY, int dx, int dy, int duration) { mCurrScroller.abortAnimation(); mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; mMinimumX = Math.min(startX, startX + dx); mMinimumY = Math.min(startY, startY + dy); mMaximumX = Math.max(startX, startX + dx); mMaximumY = Math.max(startY, startY + dy); mCurrScroller.startScroll(startX, startY, dx, dy, duration); } /** * Returns the duration of the active scroll in progress; standard, fling, * springback, or overfling. Does not account for any overflings or springback * that may result. */ public int getDuration() { return mCurrScroller.getDuration(); } /** * Start scrolling based on a fling gesture. The distance travelled will * depend on the initial velocity of the fling. * * @param startX Starting point of the scroll (X) * @param startY Starting point of the scroll (Y) * @param velocityX Initial velocity of the fling (X) measured in pixels per * second. * @param velocityY Initial velocity of the fling (Y) measured in pixels per * second * @param minX Minimum X value. The scroller will not scroll past this * point. * @param maxX Maximum X value. The scroller will not scroll past this * point. * @param minY Minimum Y value. The scroller will not scroll past this * point. * @param maxY Maximum Y value. The scroller will not scroll past this * point. */ public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) { this.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0); } /** * Start scrolling based on a fling gesture. The distance travelled will * depend on the initial velocity of the fling. * * @param startX Starting point of the scroll (X) * @param startY Starting point of the scroll (Y) * @param velocityX Initial velocity of the fling (X) measured in pixels per * second. * @param velocityY Initial velocity of the fling (Y) measured in pixels per * second * @param minX Minimum X value. The scroller will not scroll past this * point unless overX > 0. If overfling is allowed, it will use minX * as a springback boundary. * @param maxX Maximum X value. The scroller will not scroll past this * point unless overX > 0. If overfling is allowed, it will use maxX * as a springback boundary. * @param minY Minimum Y value. The scroller will not scroll past this * point unless overY > 0. If overfling is allowed, it will use minY * as a springback boundary. * @param maxY Maximum Y value. The scroller will not scroll past this * point unless overY > 0. If overfling is allowed, it will use maxY * as a springback boundary. * @param overX Overfling range. If > 0, horizontal overfling in either * direction will be possible. * @param overY Overfling range. If > 0, vertical overfling in either * direction will be possible. */ public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, int overX, int overY) { mCurrScroller = mDefaultScroller; mScrollMode = MODE_DEFAULT; mMinimumX = minX; mMaximumX = maxX; mMinimumY = minY; mMaximumY = maxY; mCurrScroller.fling(startX, startY, velocityX, velocityY, minX - overX, maxX + overX, minY - overY, maxY + overY); } /** * Returns where the scroll will end. Valid only for "fling" scrolls. * * @return The final X offset as an absolute distance from the origin. */ public int getFinalX() { return mCurrScroller.getFinalX(); } /** * Returns where the scroll will end. Valid only for "fling" scrolls. * * @return The final Y offset as an absolute distance from the origin. */ public int getFinalY() { return mCurrScroller.getFinalY(); } }
core/java/android/widget/ScrollView.java +21 −35 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.widget; import com.android.internal.R; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; Loading @@ -30,8 +32,6 @@ import android.view.ViewGroup; import android.view.ViewParent; import android.view.animation.AnimationUtils; import com.android.internal.R; import java.util.List; /** Loading Loading @@ -59,7 +59,7 @@ public class ScrollView extends FrameLayout { private long mLastScroll; private final Rect mTempRect = new Rect(); private Scroller mScroller; private OverScroller mScroller; /** * Flag to indicate that we are moving focus ourselves. This is so the Loading Loading @@ -173,7 +173,7 @@ public class ScrollView extends FrameLayout { private void initScrollView() { mScroller = new Scroller(getContext()); mScroller = new OverScroller(getContext()); setFocusable(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setWillNotDraw(false); Loading Loading @@ -378,11 +378,6 @@ public class ScrollView extends FrameLayout { return true; } if (!canScroll()) { mIsBeingDragged = false; return false; } final float y = ev.getY(); switch (action) { Loading Loading @@ -438,10 +433,6 @@ public class ScrollView extends FrameLayout { return false; } if (!canScroll()) { return false; } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } Loading @@ -468,25 +459,23 @@ public class ScrollView extends FrameLayout { final int deltaY = (int) (mLastMotionY - y); mLastMotionY = y; if (deltaY < 0) { if (mScrollY > 0) { scrollBy(0, deltaY); } } else if (deltaY > 0) { final int bottomEdge = getHeight() - mPaddingBottom; final int availableToScroll = getChildAt(0).getBottom() - mScrollY - bottomEdge; if (availableToScroll > 0) { scrollBy(0, Math.min(availableToScroll, deltaY)); } } super.scrollTo(mScrollX, mScrollY + deltaY); break; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) velocityTracker.getYVelocity(); if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) { if (getChildCount() > 0) { if ((Math.abs(initialVelocity) > mMinimumVelocity)) { fling(-initialVelocity); } else { final int bottom = Math.max(0, getChildAt(0).getHeight() - (getHeight() - mPaddingBottom - mPaddingTop)); if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, bottom)) { invalidate(); } } } if (mVelocityTracker != null) { Loading Loading @@ -915,14 +904,10 @@ public class ScrollView extends FrameLayout { int oldY = mScrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); if (getChildCount() > 0) { View child = getChildAt(0); mScrollX = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth()); mScrollY = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight()); } else { mScrollX = x; mScrollY = y; } if (oldX != mScrollX || oldY != mScrollY) { onScrollChanged(mScrollX, mScrollY, oldX, oldY); } Loading Loading @@ -1159,7 +1144,8 @@ public class ScrollView extends FrameLayout { int height = getHeight() - mPaddingBottom - mPaddingTop; int bottom = getChildAt(0).getHeight(); mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0, bottom - height); mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0, Math.max(0, bottom - height), 0, height/2); final boolean movingDown = velocityY > 0; Loading