Merge "Use autoscroller to handle drag scrolling" into jb-ub-gel-agar

This commit is contained in:
Mindy DelliCarpini
2013-07-03 21:31:15 +00:00
committed by Android (Google) Code Review
6 changed files with 581 additions and 103 deletions
-3
View File
@@ -102,9 +102,6 @@
<!-- When dragging an item, how much bigger (fixed dps) the dragged view
should be. If 0, it will not be scaled at all. -->
<dimen name="dragViewScale">12dp</dimen>
<dimen name="min_scroll_band_size">48dp</dimen>
<integer name="scroll_band_factor">20</integer>
<integer name="scroll_band_max_factor">30</integer>
<!-- Padding applied to AppWidget previews -->
<dimen name="app_widget_preview_padding_left">16dp</dimen>
+423
View File
@@ -0,0 +1,423 @@
/*
* Copyright (C) 2013 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 com.android.launcher3;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
class AutoScroller implements View.OnTouchListener, Runnable {
private static final int SCALE_RELATIVE = 0;
private static final int SCALE_ABSOLUTE = 1;
private final View mTarget;
private final RampUpScroller mScroller;
/** Interpolator used to scale velocity with touch position, may be null. */
private Interpolator mEdgeInterpolator = new AccelerateInterpolator();
/**
* Type of maximum velocity scaling to use, one of:
* <ul>
* <li>{@link #SCALE_RELATIVE}
* <li>{@link #SCALE_ABSOLUTE}
* </ul>
*/
private int mMaxVelocityScale = SCALE_RELATIVE;
/**
* Type of activation edge scaling to use, one of:
* <ul>
* <li>{@link #SCALE_RELATIVE}
* <li>{@link #SCALE_ABSOLUTE}
* </ul>
*/
private int mActivationEdgeScale = SCALE_RELATIVE;
/** Edge insets used to activate auto-scrolling. */
private RectF mActivationEdges = new RectF(0.2f, 0.2f, 0.2f, 0.2f);
/** Delay after entering an activation edge before auto-scrolling begins. */
private int mActivationDelay;
/** Maximum horizontal scrolling velocity. */
private float mMaxVelocityX = 0.001f;
/** Maximum vertical scrolling velocity. */
private float mMaxVelocityY = 0.001f;
/**
* Whether positive insets should also extend beyond the view bounds when
* auto-scrolling is already active. This allows a user to start scrolling
* at an inside edge, then move beyond the edge and continue scrolling.
*/
private boolean mExtendsBeyondEdges = true;
/** Whether to start activation immediately. */
private boolean mSkipDelay;
/** Whether to reset the scroller start time on the next animation. */
private boolean mResetScroller;
/** Whether the auto-scroller is active. */
private boolean mActive;
private long[] mScrollStart = new long[2];
/**
* If the event is within this percentage of the edge of the scrolling area,
* use accelerated scrolling.
*/
private float mFastScrollingRange = 0.8f;
/**
* Duration of time spent in accelerated scrolling area before reaching
* maximum velocity
*/
private float mDurationToMax = 2500f;
private static final int X = 0;
private static final int Y = 1;
public AutoScroller(View target) {
mTarget = target;
mScroller = new RampUpScroller(250);
mActivationDelay = ViewConfiguration.getTapTimeout();
}
/**
* Sets the maximum scrolling velocity as a fraction of the host view size
* per second. For example, a maximum Y velocity of 1 would scroll one
* vertical page per second. By default, both values are 1.
*
* @param x The maximum X velocity as a fraction of the host view width per
* second.
* @param y The maximum Y velocity as a fraction of the host view height per
* second.
*/
public void setMaximumVelocityRelative(float x, float y) {
mMaxVelocityScale = SCALE_RELATIVE;
mMaxVelocityX = x / 1000f;
mMaxVelocityY = y / 1000f;
}
/**
* Sets the maximum scrolling velocity as an absolute pixel distance per
* second. For example, a maximum Y velocity of 100 would scroll one hundred
* pixels per second.
*
* @param x The maximum X velocity as a fraction of the host view width per
* second.
* @param y The maximum Y velocity as a fraction of the host view height per
* second.
*/
public void setMaximumVelocityAbsolute(float x, float y) {
mMaxVelocityScale = SCALE_ABSOLUTE;
mMaxVelocityX = x / 1000f;
mMaxVelocityY = y / 1000f;
}
/**
* Sets the delay after entering an activation edge before activation of
* auto-scrolling. By default, the activation delay is set to
* {@link ViewConfiguration#getTapTimeout()}.
*
* @param delayMillis The delay in milliseconds.
*/
public void setActivationDelay(int delayMillis) {
mActivationDelay = delayMillis;
}
/**
* Sets the activation edges in pixels. Edges are treated as insets, so
* positive values expand into the view bounds while negative values extend
* outside the bounds.
*
* @param l The left activation edge, in pixels.
* @param t The top activation edge, in pixels.
* @param r The right activation edge, in pixels.
* @param b The bottom activation edge, in pixels.
*/
public void setEdgesAbsolute(int l, int t, int r, int b) {
mActivationEdgeScale = SCALE_ABSOLUTE;
mActivationEdges.set(l, t, r, b);
}
/**
* Whether positive insets should also extend beyond the view bounds when
* auto-scrolling is already active. This allows a user to start scrolling
* at an inside edge, then move beyond the edge and continue scrolling.
*
* @param e
*/
public void setExtendsBeyondEdges(boolean e) {
mExtendsBeyondEdges = e;
}
/**
* Sets the activation edges as fractions of the host view size. Edges are
* treated as insets, so positive values expand into the view bounds while
* negative values extend outside the bounds. By default, all values are
* 0.25.
*
* @param l The left activation edge, as a fraction of view size.
* @param t The top activation edge, as a fraction of view size.
* @param r The right activation edge, as a fraction of view size.
* @param b The bottom activation edge, as a fraction of view size.
*/
public void setEdgesRelative(float l, float t, float r, float b) {
mActivationEdgeScale = SCALE_RELATIVE;
mActivationEdges.set(l, t, r, b);
}
/**
* Sets the {@link Interpolator} used for scaling touches within activation
* edges. By default, uses the {@link AccelerateInterpolator} to gradually
* speed up scrolling.
*
* @param edgeInterpolator The interpolator to use for activation edges, or
* {@code null} to use a fixed velocity during auto-scrolling.
*/
public void setEdgeInterpolator(Interpolator edgeInterpolator) {
mEdgeInterpolator = edgeInterpolator;
}
/**
* Stop tracking scrolling.
*/
public void stop() {
stop(true);
}
/**
* Pass the rectangle defining the drawing region for the object used to
* trigger drag scrolling.
*
* @param v View on which the scrolling regions are defined
* @param r Rect defining the drawing bounds of the object being dragged
* @return whether the event was handled
*/
public boolean onTouch(View v, Rect r) {
MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, r.left, r.top, 0);
return onTouch(v, event);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
final int sourceWidth = v.getWidth();
final int sourceHeight = v.getHeight();
final float x = event.getX();
final float y = event.getY();
final float l;
final float t;
final float r;
final float b;
final RectF activationEdges = mActivationEdges;
if (mActivationEdgeScale == SCALE_ABSOLUTE) {
l = activationEdges.left;
t = activationEdges.top;
r = activationEdges.right;
b = activationEdges.bottom;
} else {
l = activationEdges.left * sourceWidth;
t = activationEdges.top * sourceHeight;
r = activationEdges.right * sourceWidth;
b = activationEdges.bottom * sourceHeight;
}
final float maxVelX;
final float maxVelY;
if (mMaxVelocityScale == SCALE_ABSOLUTE) {
maxVelX = mMaxVelocityX;
maxVelY = mMaxVelocityY;
} else {
maxVelX = mMaxVelocityX * mTarget.getWidth();
maxVelY = mMaxVelocityY * mTarget.getHeight();
}
final float velocityX = getEdgeVelocity(X, l, r, x, sourceWidth, event);
final float velocityY = getEdgeVelocity(Y, t, b, y, sourceHeight, event);
mScroller.setTargetVelocity(velocityX * maxVelX, velocityY * maxVelY);
if ((velocityX != 0 || velocityY != 0) && !mActive) {
mActive = true;
mResetScroller = true;
if (mSkipDelay) {
mTarget.postOnAnimation(this);
} else {
mSkipDelay = true;
mTarget.postOnAnimationDelayed(this, mActivationDelay);
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
stop(true);
break;
}
return false;
}
/**
* @param leading Size of the leading activation inset.
* @param trailing Size of the trailing activation inset.
* @param current Position within within the total area.
* @param size Size of the total area.
* @return The fraction of the activation area.
*/
private float getEdgeVelocity(int dir, float leading, float trailing,
float current, float size, MotionEvent ev) {
float valueLeading = 0;
if (leading > 0) {
if (current < leading) {
if (current > 0) {
// Movement up to the edge is scaled.
valueLeading = 1f - current / leading;
} else if (mActive && mExtendsBeyondEdges) {
// Movement beyond the edge is always maximum.
valueLeading = 1f;
}
}
} else if (leading < 0) {
if (current < 0) {
// Movement beyond the edge is scaled.
valueLeading = current / leading;
}
}
float valueTrailing = 0;
if (trailing > 0) {
if (current > size - trailing) {
if (current < size) {
// Movement up to the edge is scaled.
valueTrailing = 1f - (size - current) / trailing;
} else if (mActive && mExtendsBeyondEdges) {
// Movement beyond the edge is always maximum.
valueTrailing = 1f;
}
}
} else if (trailing < 0) {
if (current > size) {
// Movement beyond the edge is scaled.
valueTrailing = (size - current) / trailing;
}
}
float value = (valueTrailing - valueLeading);
if ((value > mFastScrollingRange || value < -mFastScrollingRange)
&& mScrollStart[dir] == 0) {
// within auto scrolling area
mScrollStart[dir] = ev.getEventTime();
} else {
// Outside fast scrolling area; reset duration
mScrollStart[dir] = 0;
}
final float duration = (ev.getEventTime() - mScrollStart[dir])/mDurationToMax;
final float interpolated;
if (value < 0) {
if (value < -mFastScrollingRange) {
// Close to top; use duration!
value += mEdgeInterpolator.getInterpolation(-duration);
}
interpolated = mEdgeInterpolator == null ? -1
: -mEdgeInterpolator.getInterpolation(-value);
} else if (value > 0) {
// Close to bottom; use duration
if (value > mFastScrollingRange) {
// Close to bottom; use duration!
value += mEdgeInterpolator.getInterpolation(duration);
}
interpolated = mEdgeInterpolator == null ? 1
: mEdgeInterpolator.getInterpolation(value);
} else {
mScrollStart[dir] = 0;
return 0;
}
return constrain(interpolated, -1, 1);
}
private static float constrain(float value, float min, float max) {
if (value > max) {
return max;
} else if (value < min) {
return min;
} else {
return value;
}
}
/**
* Stops auto-scrolling immediately, optionally reseting the auto-scrolling
* delay.
*
* @param reset Whether to reset the auto-scrolling delay.
*/
private void stop(boolean reset) {
mActive = false;
mSkipDelay = !reset;
mTarget.removeCallbacks(this);
}
@Override
public void run() {
if (!mActive) {
return;
}
if (mResetScroller) {
mResetScroller = false;
mScroller.start();
}
final View target = mTarget;
final RampUpScroller scroller = mScroller;
final float targetVelocityX = scroller.getTargetVelocityX();
final float targetVelocityY = scroller.getTargetVelocityY();
if ((targetVelocityY == 0 || !target.canScrollVertically(targetVelocityY > 0 ? 1 : -1)
&& (targetVelocityX == 0
|| !target.canScrollHorizontally(targetVelocityX > 0 ? 1 : -1)))) {
stop(false);
return;
}
scroller.computeScrollDelta();
final int deltaX = scroller.getDeltaX();
final int deltaY = scroller.getDeltaY();
if (target instanceof AbsListView) {
final AbsListView list = (AbsListView) target;
list.smoothScrollBy(deltaY, 0);
} else {
target.scrollBy(deltaX, deltaY);
}
target.postOnAnimation(this);
}
}
@@ -123,17 +123,16 @@ public class DragController {
* Interface to receive notifications when a drag starts or stops
*/
interface DragListener {
/**
* A drag has begun
*
*
* @param source An object representing where the drag originated
* @param info The data associated with the object that is being dragged
* @param dragAction The drag action: either {@link DragController#DRAG_ACTION_MOVE}
* or {@link DragController#DRAG_ACTION_COPY}
*/
void onDragStart(DragSource source, Object info, int dragAction);
/**
* The drag has ended
*/
@@ -514,7 +513,6 @@ public class DragController {
if (delegate != null) {
dropTarget = delegate;
}
if (mLastDropTarget != dropTarget) {
if (mLastDropTarget != null) {
mLastDropTarget.onDragExit(mDragObject);
@@ -589,6 +587,7 @@ public class DragController {
} else {
mScrollState = SCROLL_OUTSIDE_ZONE;
}
handleMoveEvent(dragLayerX, dragLayerY);
break;
case MotionEvent.ACTION_MOVE:
handleMoveEvent(dragLayerX, dragLayerY);
+1 -1
View File
@@ -123,7 +123,7 @@ public interface DropTarget {
* touch happened
* @param dragView The DragView that's being dragged around on screen.
* @param dragInfo Data associated with the object being dragged
*
*
*/
void onDrop(DragObject dragObject);
+34 -95
View File
@@ -107,22 +107,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
FolderEditText mFolderName;
private float mFolderIconPivotX;
private float mFolderIconPivotY;
private long mDragScrollStart;
/** Interpolator used to scale velocity with touch position, may be null. */
private Interpolator mEdgeInterpolator = new AccelerateInterpolator();
private static final int SCROLL_CUT_OFF_AMOUNT = 60;
private final float mDurationToMax = 300f;
private final float mMaxVelocity = 100000f/1000f;
// Aim for this amount of target area to trigger scrolling
private static float sScrollBandFactor = -1f;
private static float sScrollBandMaxFactor = -1f;
// Min size for the target area to trigger scrolling
private static int sMinScrollBandHeight = -1;
private static final float MAX_SCROLL_VELOCITY = 1500f;
private boolean mIsEditingName = false;
private InputMethodManager mInputMethodManager;
@@ -132,12 +120,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
private int DRAG_MODE_NONE = 0;
private int DRAG_MODE_REORDER = 1;
private int DRAG_MODE_SCROLL_UP = 2;
private int DRAG_MODE_SCROLL_DOWN = 3;
private int mDragMode = DRAG_MODE_NONE;
private boolean mDestroyed;
private AutoScroller mAutoScroller;
/**
* Used to inflate the Workspace from XML.
*
@@ -191,15 +179,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
if (sHintText == null) {
sHintText = res.getString(R.string.folder_hint_text);
}
if (sMinScrollBandHeight == -1) {
sMinScrollBandHeight = res.getDimensionPixelSize(R.dimen.min_scroll_band_size);
}
if (sScrollBandFactor == -1f) {
sScrollBandFactor = res.getInteger(R.integer.scroll_band_factor)/100f;
}
if (sScrollBandMaxFactor == -1f) {
sScrollBandMaxFactor = res.getInteger(R.integer.scroll_band_max_factor)/100f;
}
mLauncher = (Launcher) context;
// We need this view to be focusable in touch mode so that when text editing of the folder
// name is complete, we have something to focus on, thus hiding the cursor and giving
@@ -236,6 +215,9 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mFolderName.setSelectAllOnFocus(true);
mFolderName.setInputType(mFolderName.getInputType() |
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
mAutoScroller = new AutoScroller(mScrollView);
mAutoScroller.setMaximumVelocityAbsolute(MAX_SCROLL_VELOCITY, MAX_SCROLL_VELOCITY);
mAutoScroller.setExtendsBeyondEdges(false);
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@@ -673,83 +655,38 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
}
private Rect getDragObjectDrawingRect(View dragView, float[] r) {
final Rect drawingRect = mTempRect;
drawingRect.left = (int) r[0];
drawingRect.top = (int) r[1];
drawingRect.right = drawingRect.left + dragView.getMeasuredWidth();
drawingRect.bottom = drawingRect.top + dragView.getMeasuredHeight();
return drawingRect;
}
public void onDragOver(DragObject d) {
int scrollOffset = mScrollView.getScrollY();
int height = getMeasuredHeight();
int scrollBandHeight = Math.min((int) (height * sScrollBandMaxFactor),
(Math.max(sMinScrollBandHeight, (int) (height * sScrollBandFactor))));
float[] r = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, null);
r[0] -= getPaddingLeft();
r[1] -= getPaddingTop();
if (!mAutoScroller.onTouch(this, getDragObjectDrawingRect(d.dragView, r))) {
mTargetCell = mContent.findNearestArea((int) r[0], (int) r[1] + scrollOffset, 1, 1,
mTargetCell);
mTargetCell = mContent.findNearestArea((int) r[0], (int) r[1] + scrollOffset,
1, 1, mTargetCell);
if (isLayoutRtl()) {
mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
}
if (r[1] < scrollBandHeight && mScrollView.getScrollY() > 0) {
// Scroll up
if (mDragMode != DRAG_MODE_SCROLL_UP) {
mDragMode = DRAG_MODE_SCROLL_UP;
mDragScrollStart = System.currentTimeMillis();
scrollUp();
if (isLayoutRtl()) {
mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
}
mReorderAlarm.cancelAlarm();
} else if (r[1] > (getFolderHeight() - scrollBandHeight) && mScrollView.getScrollY() <
(mContent.getMeasuredHeight() - mScrollView.getMeasuredHeight())) {
if (mDragMode != DRAG_MODE_SCROLL_DOWN) {
mDragMode = DRAG_MODE_SCROLL_DOWN;
mDragScrollStart = System.currentTimeMillis();
scrollDown();
if (mTargetCell[0] != mPreviousTargetCell[0]
|| mTargetCell[1] != mPreviousTargetCell[1]) {
mReorderAlarm.cancelAlarm();
mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
mReorderAlarm.setAlarm(REORDER_DELAY);
mPreviousTargetCell[0] = mTargetCell[0];
mPreviousTargetCell[1] = mTargetCell[1];
mDragMode = DRAG_MODE_REORDER;
} else {
mDragMode = DRAG_MODE_NONE;
}
mReorderAlarm.cancelAlarm();
} else if (mTargetCell[0] != mPreviousTargetCell[0] || mTargetCell[1] != mPreviousTargetCell[1]) {
mReorderAlarm.cancelAlarm();
mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
mReorderAlarm.setAlarm(REORDER_DELAY);
mPreviousTargetCell[0] = mTargetCell[0];
mPreviousTargetCell[1] = mTargetCell[1];
mDragMode = DRAG_MODE_REORDER;
} else {
mDragMode = DRAG_MODE_NONE;
}
}
Runnable mScrollUpRunnable = new Runnable() {
@Override
public void run() {
scrollUp();
}
};
Runnable mScrollDownRunnable = new Runnable() {
@Override
public void run() {
scrollDown();
}
};
private int getVelocity() {
float duration = (System.currentTimeMillis() - mDragScrollStart)/mDurationToMax;
return (int) Math.min(mMaxVelocity,
(int) (mEdgeInterpolator.getInterpolation(duration) * mMaxVelocity));
}
private void scrollUp() {
if (mDragMode == DRAG_MODE_SCROLL_UP) {
mScrollView.setScrollY(mScrollView.getScrollY() - getVelocity());
invalidate();
post(mScrollUpRunnable);
}
}
private void scrollDown() {
if (mDragMode == DRAG_MODE_SCROLL_DOWN) {
mScrollView.setScrollY(mScrollView.getScrollY() + getVelocity());
invalidate();
post(mScrollDownRunnable);
}
}
@@ -794,8 +731,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
public void onDragExit(DragObject d) {
// We only close the folder if this is a true drag exit, ie. not because a drop
// has occurred above the folder.
// Exiting folder; stop the auto scroller.
mAutoScroller.stop();
// We only close the folder if this is a true drag exit, ie. not because
// a drop has occurred above the folder.
if (!d.dragComplete) {
mOnExitAlarm.setOnAlarmListener(mOnExitAlarmListener);
mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
@@ -0,0 +1,120 @@
/*
* Copyright (C) 2013 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 com.android.launcher3;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
/**
* Scroller that gradually reaches a target velocity.
*/
class RampUpScroller {
private final Interpolator mInterpolator;
private final long mRampUpTime;
private long mStartTime;
private long mDeltaTime;
private float mTargetVelocityX;
private float mTargetVelocityY;
private int mDeltaX;
private int mDeltaY;
/**
* Creates a new ramp-up scroller that reaches full velocity after a
* specified duration.
*
* @param rampUpTime Duration before the scroller reaches target velocity.
*/
public RampUpScroller(long rampUpTime) {
mInterpolator = new AccelerateInterpolator();
mRampUpTime = rampUpTime;
}
/**
* Starts the scroller at the current animation time.
*/
public void start() {
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDeltaTime = mStartTime;
}
/**
* Computes the current scroll deltas. This usually only be called after
* starting the scroller with {@link #start()}.
*
* @see #getDeltaX()
* @see #getDeltaY()
*/
public void computeScrollDelta() {
final long currentTime = AnimationUtils.currentAnimationTimeMillis();
final long elapsedSinceStart = currentTime - mStartTime;
final float scale;
if (elapsedSinceStart < mRampUpTime) {
scale = mInterpolator.getInterpolation((float) elapsedSinceStart / mRampUpTime);
} else {
scale = 1f;
}
final long elapsedSinceDelta = currentTime - mDeltaTime;
mDeltaTime = currentTime;
mDeltaX = (int) (elapsedSinceDelta * scale * mTargetVelocityX);
mDeltaY = (int) (elapsedSinceDelta * scale * mTargetVelocityY);
}
/**
* Sets the target velocity for this scroller.
*
* @param x The target X velocity in pixels per millisecond.
* @param y The target Y velocity in pixels per millisecond.
*/
public void setTargetVelocity(float x, float y) {
mTargetVelocityX = x;
mTargetVelocityY = y;
}
/**
* @return The target X velocity for this scroller.
*/
public float getTargetVelocityX() {
return mTargetVelocityX;
}
/**
* @return The target Y velocity for this scroller.
*/
public float getTargetVelocityY() {
return mTargetVelocityY;
}
/**
* The distance traveled in the X-coordinate computed by the last call to
* {@link #computeScrollDelta()}.
*/
public int getDeltaX() {
return mDeltaX;
}
/**
* The distance traveled in the Y-coordinate computed by the last call to
* {@link #computeScrollDelta()}.
*/
public int getDeltaY() {
return mDeltaY;
}
}