AutoScrollHelperpublic abstract class AutoScrollHelper extends Object implements View.OnTouchListenerAutoScrollHelper is a utility class for adding automatic edge-triggered
scrolling to Views.
Note: Implementing classes are responsible for overriding the
{@link #scrollTargetBy}, {@link #canTargetScrollHorizontally}, and
{@link #canTargetScrollVertically} methods. See
{@link ListViewAutoScrollHelper} for a {@link android.widget.ListView}
-specific implementation.
Activation Automatic scrolling starts when the user touches within
an activation area. By default, activation areas are defined as the top,
left, right, and bottom 20% of the host view's total area. Touching within
the top activation area scrolls up, left scrolls to the left, and so on.
As the user touches closer to the extreme edge of the activation area,
scrolling accelerates up to a maximum velocity. When using the default edge
type, {@link #EDGE_TYPE_INSIDE_EXTEND}, moving outside of the view bounds
will scroll at the maximum velocity.
The following activation properties may be configured:
- Delay after entering activation area before auto-scrolling begins, see
{@link #setActivationDelay}. Default value is
{@link ViewConfiguration#getTapTimeout()} to avoid conflicting with taps.
- Location of activation areas, see {@link #setEdgeType}. Default value is
{@link #EDGE_TYPE_INSIDE_EXTEND}.
- Size of activation areas relative to view size, see
{@link #setRelativeEdges}. Default value is 20% for both vertical and
horizontal edges.
- Maximum size used to constrain relative size, see
{@link #setMaximumEdges}. Default value is {@link #NO_MAX}.
Scrolling When automatic scrolling is active, the helper will
repeatedly call {@link #scrollTargetBy} to apply new scrolling offsets.
The following scrolling properties may be configured:
- Acceleration ramp-up duration, see {@link #setRampUpDuration}. Default
value is 500 milliseconds.
- Acceleration ramp-down duration, see {@link #setRampDownDuration}.
Default value is 500 milliseconds.
- Target velocity relative to view size, see {@link #setRelativeVelocity}.
Default value is 100% per second for both vertical and horizontal.
- Minimum velocity used to constrain relative velocity, see
{@link #setMinimumVelocity}. When set, scrolling will accelerate to the
larger of either this value or the relative target value. Default value is
approximately 5 centimeters or 315 dips per second.
- Maximum velocity used to constrain relative velocity, see
{@link #setMaximumVelocity}. Default value is approximately 25 centimeters or
1575 dips per second.
|
Fields Summary |
---|
public static final float | RELATIVE_UNSPECIFIEDConstant passed to {@link #setRelativeEdges} or
{@link #setRelativeVelocity}. Using this value ensures that the computed
relative value is ignored and the absolute maximum value is always used. | public static final float | NO_MAXConstant passed to {@link #setMaximumEdges}, {@link #setMaximumVelocity},
or {@link #setMinimumVelocity}. Using this value ensures that the
computed relative value is always used without constraining to a
particular minimum or maximum value. | public static final float | NO_MINConstant passed to {@link #setMaximumEdges}, or
{@link #setMaximumVelocity}, or {@link #setMinimumVelocity}. Using this
value ensures that the computed relative value is always used without
constraining to a particular minimum or maximum value. | public static final int | EDGE_TYPE_INSIDEEdge type that specifies an activation area starting at the view bounds
and extending inward. Moving outside the view bounds will stop scrolling. | public static final int | EDGE_TYPE_INSIDE_EXTENDEdge type that specifies an activation area starting at the view bounds
and extending inward. After activation begins, moving outside the view
bounds will continue scrolling. | public static final int | EDGE_TYPE_OUTSIDEEdge type that specifies an activation area starting at the view bounds
and extending outward. Moving inside the view bounds will stop scrolling. | private static final int | HORIZONTAL | private static final int | VERTICAL | private final ClampedScroller | mScrollerScroller used to control acceleration toward maximum velocity. | private final android.view.animation.Interpolator | mEdgeInterpolatorInterpolator used to scale velocity with touch position. | private final android.view.View | mTargetThe view to auto-scroll. Might not be the source of touch events. | private Runnable | mRunnableRunnable used to animate scrolling. | private float[] | mRelativeEdgesEdge insets used to activate auto-scrolling. | private float[] | mMaximumEdgesClamping values for edge insets used to activate auto-scrolling. | private int | mEdgeTypeThe type of edge being used. | private int | mActivationDelayDelay after entering an activation edge before auto-scrolling begins. | private float[] | mRelativeVelocityRelative scrolling velocity at maximum edge distance. | private float[] | mMinimumVelocityClamping values used for scrolling velocity. | private float[] | mMaximumVelocityClamping values used for scrolling velocity. | private boolean | mAlreadyDelayedWhether to start activation immediately. | private boolean | mNeedsResetWhether to reset the scroller start time on the next animation. | private boolean | mNeedsCancelWhether to send a cancel motion event to the target view. | private boolean | mAnimatingWhether the auto-scroller is actively scrolling. | private boolean | mEnabledWhether the auto-scroller is enabled. | private boolean | mExclusiveWhether the auto-scroller consumes events when scrolling. | private static final int | DEFAULT_EDGE_TYPE | private static final int | DEFAULT_MINIMUM_VELOCITY_DIPS | private static final int | DEFAULT_MAXIMUM_VELOCITY_DIPS | private static final float | DEFAULT_MAXIMUM_EDGE | private static final float | DEFAULT_RELATIVE_EDGE | private static final float | DEFAULT_RELATIVE_VELOCITY | private static final int | DEFAULT_ACTIVATION_DELAY | private static final int | DEFAULT_RAMP_UP_DURATION | private static final int | DEFAULT_RAMP_DOWN_DURATION |
Constructors Summary |
---|
public AutoScrollHelper(android.view.View target)Creates a new helper for scrolling the specified target view.
The resulting helper may be configured by chaining setter calls and
should be set as a touch listener on the target view.
By default, the helper is disabled and will not respond to touch events
until it is enabled using {@link #setEnabled}.
mTarget = target;
final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
final int maxVelocity = (int) (DEFAULT_MAXIMUM_VELOCITY_DIPS * metrics.density + 0.5f);
final int minVelocity = (int) (DEFAULT_MINIMUM_VELOCITY_DIPS * metrics.density + 0.5f);
setMaximumVelocity(maxVelocity, maxVelocity);
setMinimumVelocity(minVelocity, minVelocity);
setEdgeType(DEFAULT_EDGE_TYPE);
setMaximumEdges(DEFAULT_MAXIMUM_EDGE, DEFAULT_MAXIMUM_EDGE);
setRelativeEdges(DEFAULT_RELATIVE_EDGE, DEFAULT_RELATIVE_EDGE);
setRelativeVelocity(DEFAULT_RELATIVE_VELOCITY, DEFAULT_RELATIVE_VELOCITY);
setActivationDelay(DEFAULT_ACTIVATION_DELAY);
setRampUpDuration(DEFAULT_RAMP_UP_DURATION);
setRampDownDuration(DEFAULT_RAMP_DOWN_DURATION);
|
Methods Summary |
---|
public abstract boolean | canTargetScrollHorizontally(int direction)Override this method to return whether the target view can be scrolled
horizontally in a certain direction.
| public abstract boolean | canTargetScrollVertically(int direction)Override this method to return whether the target view can be scrolled
vertically in a certain direction.
| private void | cancelTargetTouch()Sends a {@link MotionEvent#ACTION_CANCEL} event to the target view,
canceling any ongoing touch events.
final long eventTime = SystemClock.uptimeMillis();
final MotionEvent cancel = MotionEvent.obtain(
eventTime, eventTime, MotionEvent.ACTION_CANCEL, 0, 0, 0);
mTarget.onTouchEvent(cancel);
cancel.recycle();
| private float | computeTargetVelocity(int direction, float coordinate, float srcSize, float dstSize)
final float relativeEdge = mRelativeEdges[direction];
final float maximumEdge = mMaximumEdges[direction];
final float value = getEdgeValue(relativeEdge, srcSize, maximumEdge, coordinate);
if (value == 0) {
// The edge in this direction is not activated.
return 0;
}
final float relativeVelocity = mRelativeVelocity[direction];
final float minimumVelocity = mMinimumVelocity[direction];
final float maximumVelocity = mMaximumVelocity[direction];
final float targetVelocity = relativeVelocity * dstSize;
// Target velocity is adjusted for interpolated edge position, then
// clamped to the minimum and maximum values. Later, this value will be
// adjusted for time-based acceleration.
if (value > 0) {
return constrain(value * targetVelocity, minimumVelocity, maximumVelocity);
} else {
return -constrain(-value * targetVelocity, minimumVelocity, maximumVelocity);
}
| private static int | constrain(int value, int min, int max)
if (value > max) {
return max;
} else if (value < min) {
return min;
} else {
return value;
}
| private static float | constrain(float value, float min, float max)
if (value > max) {
return max;
} else if (value < min) {
return min;
} else {
return value;
}
| private float | constrainEdgeValue(float current, float leading)
if (leading == 0) {
return 0;
}
switch (mEdgeType) {
case EDGE_TYPE_INSIDE:
case EDGE_TYPE_INSIDE_EXTEND:
if (current < leading) {
if (current >= 0) {
// Movement up to the edge is scaled.
return 1f - current / leading;
} else if (mAnimating && (mEdgeType == EDGE_TYPE_INSIDE_EXTEND)) {
// Movement beyond the edge is always maximum.
return 1f;
}
}
break;
case EDGE_TYPE_OUTSIDE:
if (current < 0) {
// Movement beyond the edge is scaled.
return current / -leading;
}
break;
}
return 0;
| private float | getEdgeValue(float relativeValue, float size, float maxValue, float current)Returns the interpolated position of a touch point relative to an edge
defined by its relative inset, its maximum absolute inset, and the edge
interpolator.
// For now, leading and trailing edges are always the same size.
final float edgeSize = constrain(relativeValue * size, NO_MIN, maxValue);
final float valueLeading = constrainEdgeValue(current, edgeSize);
final float valueTrailing = constrainEdgeValue(size - current, edgeSize);
final float value = (valueTrailing - valueLeading);
final float interpolated;
if (value < 0) {
interpolated = -mEdgeInterpolator.getInterpolation(-value);
} else if (value > 0) {
interpolated = mEdgeInterpolator.getInterpolation(value);
} else {
return 0;
}
return constrain(interpolated, -1, 1);
| public boolean | isEnabled()
return mEnabled;
| public boolean | isExclusive()Indicates whether the scroll helper handles touch events exclusively
during scrolling.
return mExclusive;
| public boolean | onTouch(android.view.View v, android.view.MotionEvent event)Handles touch events by activating automatic scrolling, adjusting scroll
velocity, or stopping.
If {@link #isExclusive()} is false, always returns false so that
the host view may handle touch events. Otherwise, returns true when
automatic scrolling is active and false otherwise.
if (!mEnabled) {
return false;
}
final int action = MotionEventCompat.getActionMasked(event);
switch (action) {
case MotionEvent.ACTION_DOWN:
mNeedsCancel = true;
mAlreadyDelayed = false;
// $FALL-THROUGH$
case MotionEvent.ACTION_MOVE:
final float xTargetVelocity = computeTargetVelocity(
HORIZONTAL, event.getX(), v.getWidth(), mTarget.getWidth());
final float yTargetVelocity = computeTargetVelocity(
VERTICAL, event.getY(), v.getHeight(), mTarget.getHeight());
mScroller.setTargetVelocity(xTargetVelocity, yTargetVelocity);
// If the auto scroller was not previously active, but it should
// be, then update the state and start animations.
if (!mAnimating && shouldAnimate()) {
startAnimating();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
requestStop();
break;
}
return mExclusive && mAnimating;
| private void | requestStop()Requests that the scroll animation slow to a stop. If there is an
activation delay, this may occur between posting the animation and
actually running it.
if (mNeedsReset) {
// The animation has been posted, but hasn't run yet. Manually
// stopping animation will prevent it from running.
mAnimating = false;
} else {
mScroller.requestStop();
}
| public abstract void | scrollTargetBy(int deltaX, int deltaY)Override this method to scroll the target view by the specified number of
pixels.
| public android.support.v4.widget.AutoScrollHelper | setActivationDelay(int delayMillis)Sets the delay after entering an activation edge before activation of
auto-scrolling. By default, the activation delay is set to
{@link ViewConfiguration#getTapTimeout()}.
Specifying a delay of zero will start auto-scrolling immediately after
the touch position enters an activation edge.
mActivationDelay = delayMillis;
return this;
| public android.support.v4.widget.AutoScrollHelper | setEdgeType(int type)Sets the activation edge type, one of:
- {@link #EDGE_TYPE_INSIDE} for edges that respond to touches inside
the bounds of the host view. If touch moves outside the bounds, scrolling
will stop.
- {@link #EDGE_TYPE_INSIDE_EXTEND} for inside edges that continued to
scroll when touch moves outside the bounds of the host view.
- {@link #EDGE_TYPE_OUTSIDE} for edges that only respond to touches
that move outside the bounds of the host view.
mEdgeType = type;
return this;
| public android.support.v4.widget.AutoScrollHelper | setEnabled(boolean enabled)Sets whether the scroll helper is enabled and should respond to touch
events.
if (mEnabled && !enabled) {
requestStop();
}
mEnabled = enabled;
return this;
| public android.support.v4.widget.AutoScrollHelper | setExclusive(boolean exclusive)Enables or disables exclusive handling of touch events during scrolling.
By default, exclusive handling is disabled and the target view receives
all touch events.
When enabled, {@link #onTouch} will return true if the helper is
currently scrolling and false otherwise.
mExclusive = exclusive;
return this;
| public android.support.v4.widget.AutoScrollHelper | setMaximumEdges(float horizontalMax, float verticalMax)Sets the absolute maximum edge size.
If relative edge size is not specified, activation edges will always be
the maximum edge size. If both relative and maximum edges are specified,
the maximum edge will be used to constrain the calculated relative edge
size.
mMaximumEdges[HORIZONTAL] = horizontalMax;
mMaximumEdges[VERTICAL] = verticalMax;
return this;
| public android.support.v4.widget.AutoScrollHelper | setMaximumVelocity(float horizontalMax, float verticalMax)Sets the absolute maximum scrolling velocity.
If relative velocity is not specified, scrolling will always reach the
same maximum velocity. If both relative and maximum velocities are
specified, the maximum velocity will be used to clamp the calculated
relative velocity.
mMaximumVelocity[HORIZONTAL] = horizontalMax / 1000f;
mMaximumVelocity[VERTICAL] = verticalMax / 1000f;
return this;
| public android.support.v4.widget.AutoScrollHelper | setMinimumVelocity(float horizontalMin, float verticalMin)Sets the absolute minimum scrolling velocity.
If both relative and minimum velocities are specified, the minimum
velocity will be used to clamp the calculated relative velocity.
mMinimumVelocity[HORIZONTAL] = horizontalMin / 1000f;
mMinimumVelocity[VERTICAL] = verticalMin / 1000f;
return this;
| public android.support.v4.widget.AutoScrollHelper | setRampDownDuration(int durationMillis)Sets the amount of time after de-activation of auto-scrolling that is
takes to slow to a stop.
Specifying a duration greater than zero prevents sudden jumps in
velocity.
mScroller.setRampDownDuration(durationMillis);
return this;
| public android.support.v4.widget.AutoScrollHelper | setRampUpDuration(int durationMillis)Sets the amount of time after activation of auto-scrolling that is takes
to reach target velocity for the current touch position.
Specifying a duration greater than zero prevents sudden jumps in
velocity.
mScroller.setRampUpDuration(durationMillis);
return this;
| public android.support.v4.widget.AutoScrollHelper | setRelativeEdges(float horizontal, float vertical)Sets the activation edge size relative to the host view's dimensions.
If both relative and maximum edges are specified, the maximum edge will
be used to constrain the calculated relative edge size.
mRelativeEdges[HORIZONTAL] = horizontal;
mRelativeEdges[VERTICAL] = vertical;
return this;
| public android.support.v4.widget.AutoScrollHelper | setRelativeVelocity(float horizontal, float vertical)Sets the target scrolling velocity relative to the host view's
dimensions.
If both relative and maximum velocities are specified, the maximum
velocity will be used to clamp the calculated relative velocity.
mRelativeVelocity[HORIZONTAL] = horizontal / 1000f;
mRelativeVelocity[VERTICAL] = vertical / 1000f;
return this;
| private boolean | shouldAnimate()
final ClampedScroller scroller = mScroller;
final int verticalDirection = scroller.getVerticalDirection();
final int horizontalDirection = scroller.getHorizontalDirection();
return verticalDirection != 0 && canTargetScrollVertically(verticalDirection)
|| horizontalDirection != 0 && canTargetScrollHorizontally(horizontalDirection);
| private void | startAnimating()Starts the scroll animation.
if (mRunnable == null) {
mRunnable = new ScrollAnimationRunnable();
}
mAnimating = true;
mNeedsReset = true;
if (!mAlreadyDelayed && mActivationDelay > 0) {
ViewCompat.postOnAnimationDelayed(mTarget, mRunnable, mActivationDelay);
} else {
mRunnable.run();
}
// If we start animating again before the user lifts their finger, we
// already know it's not a tap and don't need an activation delay.
mAlreadyDelayed = true;
|
|