1eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette/* 2eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Copyright (C) 2013 The Android Open Source Project 3eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 4eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 5eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * you may not use this file except in compliance with the License. 6eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * You may obtain a copy of the License at 7eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 8eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * http://www.apache.org/licenses/LICENSE-2.0 9eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 10eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Unless required by applicable law or agreed to in writing, software 11eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 12eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * See the License for the specific language governing permissions and 14eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * limitations under the License. 15eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 16eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 17eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverettepackage android.support.v4.widget; 18eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 19eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.content.res.Resources; 206cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viveretteimport android.os.SystemClock; 21eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.support.v4.view.MotionEventCompat; 22eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.support.v4.view.ViewCompat; 23eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.util.DisplayMetrics; 24eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.MotionEvent; 25eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.View; 26eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.ViewConfiguration; 27eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.animation.AccelerateInterpolator; 28eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.animation.AnimationUtils; 29eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.animation.Interpolator; 30eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 31eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette/** 32eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * AutoScrollHelper is a utility class for adding automatic edge-triggered 33eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * scrolling to Views. 34eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 35eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <b>Note:</b> Implementing classes are responsible for overriding the 36504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * {@link #scrollTargetBy}, {@link #canTargetScrollHorizontally}, and 37504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * {@link #canTargetScrollVertically} methods. See 38eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link ListViewAutoScrollHelper} for a {@link android.widget.ListView} 39eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * -specific implementation. 40eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 41eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <h1>Activation</h1> Automatic scrolling starts when the user touches within 42eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * an activation area. By default, activation areas are defined as the top, 43eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * left, right, and bottom 20% of the host view's total area. Touching within 44eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the top activation area scrolls up, left scrolls to the left, and so on. 45eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 46eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * As the user touches closer to the extreme edge of the activation area, 47eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * scrolling accelerates up to a maximum velocity. When using the default edge 48eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * type, {@link #EDGE_TYPE_INSIDE_EXTEND}, moving outside of the view bounds 49eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * will scroll at the maximum velocity. 50eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 51eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The following activation properties may be configured: 52eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <ul> 53eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Delay after entering activation area before auto-scrolling begins, see 54eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setActivationDelay}. Default value is 55eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link ViewConfiguration#getTapTimeout()} to avoid conflicting with taps. 56eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Location of activation areas, see {@link #setEdgeType}. Default value is 57eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #EDGE_TYPE_INSIDE_EXTEND}. 58eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Size of activation areas relative to view size, see 59eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setRelativeEdges}. Default value is 20% for both vertical and 60eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * horizontal edges. 61eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Maximum size used to constrain relative size, see 62eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setMaximumEdges}. Default value is {@link #NO_MAX}. 63eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * </ul> 64eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <h1>Scrolling</h1> When automatic scrolling is active, the helper will 65504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * repeatedly call {@link #scrollTargetBy} to apply new scrolling offsets. 66eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 67eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The following scrolling properties may be configured: 68eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <ul> 69eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Acceleration ramp-up duration, see {@link #setRampUpDuration}. Default 702155135a266e288854714775d8a9ba7d8eddfd2aMindy Pereira * value is 500 milliseconds. 71504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * <li>Acceleration ramp-down duration, see {@link #setRampDownDuration}. 72504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Default value is 500 milliseconds. 73eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Target velocity relative to view size, see {@link #setRelativeVelocity}. 74eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Default value is 100% per second for both vertical and horizontal. 75eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Minimum velocity used to constrain relative velocity, see 76eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setMinimumVelocity}. When set, scrolling will accelerate to the 77eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * larger of either this value or the relative target value. Default value is 78eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * approximately 5 centimeters or 315 dips per second. 79eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Maximum velocity used to constrain relative velocity, see 80eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setMaximumVelocity}. Default value is approximately 25 centimeters or 81eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 1575 dips per second. 82eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * </ul> 83eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 84eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverettepublic abstract class AutoScrollHelper implements View.OnTouchListener { 85eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 86eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Constant passed to {@link #setRelativeEdges} or 87eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setRelativeVelocity}. Using this value ensures that the computed 88eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * relative value is ignored and the absolute maximum value is always used. 89eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 90eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final float RELATIVE_UNSPECIFIED = 0; 91eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 92eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 93eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Constant passed to {@link #setMaximumEdges}, {@link #setMaximumVelocity}, 94eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * or {@link #setMinimumVelocity}. Using this value ensures that the 95eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * computed relative value is always used without constraining to a 96eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * particular minimum or maximum value. 97eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 98eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final float NO_MAX = Float.MAX_VALUE; 99eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 100eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 101eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Constant passed to {@link #setMaximumEdges}, or 102eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setMaximumVelocity}, or {@link #setMinimumVelocity}. Using this 103eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * value ensures that the computed relative value is always used without 104eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * constraining to a particular minimum or maximum value. 105eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 106eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final float NO_MIN = 0; 107eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 108eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 109eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Edge type that specifies an activation area starting at the view bounds 110eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * and extending inward. Moving outside the view bounds will stop scrolling. 111eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 112eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #setEdgeType 113eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 114eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final int EDGE_TYPE_INSIDE = 0; 115eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 116eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 117eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Edge type that specifies an activation area starting at the view bounds 118eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * and extending inward. After activation begins, moving outside the view 119eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * bounds will continue scrolling. 120eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 121eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #setEdgeType 122eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 123eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final int EDGE_TYPE_INSIDE_EXTEND = 1; 124eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 125eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 126eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Edge type that specifies an activation area starting at the view bounds 127eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * and extending outward. Moving inside the view bounds will stop scrolling. 128eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 129eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #setEdgeType 130eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 131eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final int EDGE_TYPE_OUTSIDE = 2; 132eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 133eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int HORIZONTAL = 0; 134eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int VERTICAL = 1; 135eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 136eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Scroller used to control acceleration toward maximum velocity. */ 137eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private final ClampedScroller mScroller = new ClampedScroller(); 138eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 139eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Interpolator used to scale velocity with touch position. */ 140eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private final Interpolator mEdgeInterpolator = new AccelerateInterpolator(); 141eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 142eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** The view to auto-scroll. Might not be the source of touch events. */ 143eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private final View mTarget; 144eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 145eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Runnable used to animate scrolling. */ 146eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private Runnable mRunnable; 147eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 148eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Edge insets used to activate auto-scrolling. */ 149eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mRelativeEdges = new float[] { RELATIVE_UNSPECIFIED, RELATIVE_UNSPECIFIED }; 150eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 151eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Clamping values for edge insets used to activate auto-scrolling. */ 152eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mMaximumEdges = new float[] { NO_MAX, NO_MAX }; 153eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 154eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** The type of edge being used. */ 155eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private int mEdgeType; 156eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 157eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Delay after entering an activation edge before auto-scrolling begins. */ 158eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private int mActivationDelay; 159eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 160eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Relative scrolling velocity at maximum edge distance. */ 161eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mRelativeVelocity = new float[] { RELATIVE_UNSPECIFIED, RELATIVE_UNSPECIFIED }; 162eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 163eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Clamping values used for scrolling velocity. */ 164eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mMinimumVelocity = new float[] { NO_MIN, NO_MIN }; 165eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 166eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Clamping values used for scrolling velocity. */ 167eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mMaximumVelocity = new float[] { NO_MAX, NO_MAX }; 168eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 169eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Whether to start activation immediately. */ 170504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private boolean mAlreadyDelayed; 171eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 172eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Whether to reset the scroller start time on the next animation. */ 173504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private boolean mNeedsReset; 174eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 175504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** Whether to send a cancel motion event to the target view. */ 176504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private boolean mNeedsCancel; 177eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 178504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** Whether the auto-scroller is actively scrolling. */ 179504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private boolean mAnimating; 1806cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 181eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Whether the auto-scroller is enabled. */ 182eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private boolean mEnabled; 183eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 1846cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette /** Whether the auto-scroller consumes events when scrolling. */ 185504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private boolean mExclusive; 1866cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 187eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // Default values. 188eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int DEFAULT_EDGE_TYPE = EDGE_TYPE_INSIDE_EXTEND; 189eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int DEFAULT_MINIMUM_VELOCITY_DIPS = 315; 190eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int DEFAULT_MAXIMUM_VELOCITY_DIPS = 1575; 191eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final float DEFAULT_MAXIMUM_EDGE = NO_MAX; 192eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final float DEFAULT_RELATIVE_EDGE = 0.2f; 193eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final float DEFAULT_RELATIVE_VELOCITY = 1f; 194eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int DEFAULT_ACTIVATION_DELAY = ViewConfiguration.getTapTimeout(); 1952155135a266e288854714775d8a9ba7d8eddfd2aMindy Pereira private static final int DEFAULT_RAMP_UP_DURATION = 500; 196504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private static final int DEFAULT_RAMP_DOWN_DURATION = 500; 197eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 198eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 199eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Creates a new helper for scrolling the specified target view. 200eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 201eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The resulting helper may be configured by chaining setter calls and 202eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * should be set as a touch listener on the target view. 203eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 204eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * By default, the helper is disabled and will not respond to touch events 205eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * until it is enabled using {@link #setEnabled}. 206eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 207eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param target The view to automatically scroll. 208eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 209eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper(View target) { 210eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mTarget = target; 211eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 212eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); 213eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int maxVelocity = (int) (DEFAULT_MAXIMUM_VELOCITY_DIPS * metrics.density + 0.5f); 214eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int minVelocity = (int) (DEFAULT_MINIMUM_VELOCITY_DIPS * metrics.density + 0.5f); 215eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setMaximumVelocity(maxVelocity, maxVelocity); 216eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setMinimumVelocity(minVelocity, minVelocity); 217eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 218eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setEdgeType(DEFAULT_EDGE_TYPE); 219eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setMaximumEdges(DEFAULT_MAXIMUM_EDGE, DEFAULT_MAXIMUM_EDGE); 220eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setRelativeEdges(DEFAULT_RELATIVE_EDGE, DEFAULT_RELATIVE_EDGE); 221eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setRelativeVelocity(DEFAULT_RELATIVE_VELOCITY, DEFAULT_RELATIVE_VELOCITY); 222eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setActivationDelay(DEFAULT_ACTIVATION_DELAY); 223eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setRampUpDuration(DEFAULT_RAMP_UP_DURATION); 224504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette setRampDownDuration(DEFAULT_RAMP_DOWN_DURATION); 225eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 226eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 227eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 228eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets whether the scroll helper is enabled and should respond to touch 229eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * events. 230eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 231eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param enabled Whether the scroll helper is enabled. 232eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 233eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 234eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setEnabled(boolean enabled) { 235504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mEnabled && !enabled) { 236504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette requestStop(); 237eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 238eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 239eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mEnabled = enabled; 240eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 241eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 242eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 243eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 244eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return True if this helper is enabled and responding to touch events. 245eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 246eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public boolean isEnabled() { 247eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return mEnabled; 248eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 249eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 250eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 2516cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * Enables or disables exclusive handling of touch events during scrolling. 2526cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * By default, exclusive handling is disabled and the target view receives 2536cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * all touch events. 2546cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * <p> 2556cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * When enabled, {@link #onTouch} will return true if the helper is 2566cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * currently scrolling and false otherwise. 2576cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * 258504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param exclusive True to exclusively handle touch events during scrolling, 2596cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * false to allow the target view to receive all touch events. 260504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return The scroll helper, which may used to chain setter calls. 2616cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette */ 262504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public AutoScrollHelper setExclusive(boolean exclusive) { 263504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mExclusive = exclusive; 264504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return this; 2656cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette } 2666cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 2676cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette /** 2686cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * Indicates whether the scroll helper handles touch events exclusively 2696cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * during scrolling. 2706cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * 2716cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * @return True if exclusive handling of touch events during scrolling is 2726cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * enabled, false otherwise. 273504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @see #setExclusive(boolean) 2746cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette */ 275504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public boolean isExclusive() { 276504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return mExclusive; 2776cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette } 2786cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 2796cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette /** 280eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the absolute maximum scrolling velocity. 281eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 282eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If relative velocity is not specified, scrolling will always reach the 283eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * same maximum velocity. If both relative and maximum velocities are 284eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * specified, the maximum velocity will be used to clamp the calculated 285eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * relative velocity. 286eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 287eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontalMax The maximum horizontal scrolling velocity, or 288eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MAX} to leave the relative value unconstrained. 289eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param verticalMax The maximum vertical scrolling velocity, or 290eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MAX} to leave the relative value unconstrained. 291eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 292eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 293eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setMaximumVelocity(float horizontalMax, float verticalMax) { 294eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMaximumVelocity[HORIZONTAL] = horizontalMax / 1000f; 295eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMaximumVelocity[VERTICAL] = verticalMax / 1000f; 296eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 297eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 298eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 299eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 300eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the absolute minimum scrolling velocity. 301eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 302eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If both relative and minimum velocities are specified, the minimum 303eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * velocity will be used to clamp the calculated relative velocity. 304eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 305eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontalMin The minimum horizontal scrolling velocity, or 306eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MIN} to leave the relative value unconstrained. 307eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param verticalMin The minimum vertical scrolling velocity, or 308eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MIN} to leave the relative value unconstrained. 309eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 310eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 311eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setMinimumVelocity(float horizontalMin, float verticalMin) { 312eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMinimumVelocity[HORIZONTAL] = horizontalMin / 1000f; 313eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMinimumVelocity[VERTICAL] = verticalMin / 1000f; 314eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 315eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 316eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 317eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 318eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the target scrolling velocity relative to the host view's 319eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * dimensions. 320eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 321eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If both relative and maximum velocities are specified, the maximum 322eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * velocity will be used to clamp the calculated relative velocity. 323eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 324eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontal The target horizontal velocity as a fraction of the 325eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * host view width per second, or {@link #RELATIVE_UNSPECIFIED} 326eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * to ignore. 327eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param vertical The target vertical velocity as a fraction of the host 328eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * view height per second, or {@link #RELATIVE_UNSPECIFIED} to 329eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * ignore. 330eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 331eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 332eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setRelativeVelocity(float horizontal, float vertical) { 333eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mRelativeVelocity[HORIZONTAL] = horizontal / 1000f; 334eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mRelativeVelocity[VERTICAL] = vertical / 1000f; 335eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 336eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 337eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 338eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 339eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the activation edge type, one of: 340eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <ul> 341eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>{@link #EDGE_TYPE_INSIDE} for edges that respond to touches inside 342eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the bounds of the host view. If touch moves outside the bounds, scrolling 343eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * will stop. 344eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>{@link #EDGE_TYPE_INSIDE_EXTEND} for inside edges that continued to 345eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * scroll when touch moves outside the bounds of the host view. 346eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>{@link #EDGE_TYPE_OUTSIDE} for edges that only respond to touches 347eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * that move outside the bounds of the host view. 348eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * </ul> 349eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 350eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param type The type of edge to use. 351eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 352eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 353eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setEdgeType(int type) { 354eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mEdgeType = type; 355eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 356eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 357eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 358eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 359eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the activation edge size relative to the host view's dimensions. 360eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 361eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If both relative and maximum edges are specified, the maximum edge will 362eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * be used to constrain the calculated relative edge size. 363eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 364eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontal The horizontal edge size as a fraction of the host view 365eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * width, or {@link #RELATIVE_UNSPECIFIED} to always use the 366eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * maximum value. 367eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param vertical The vertical edge size as a fraction of the host view 368eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * height, or {@link #RELATIVE_UNSPECIFIED} to always use the 369eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * maximum value. 370eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 371eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 372eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setRelativeEdges(float horizontal, float vertical) { 373eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mRelativeEdges[HORIZONTAL] = horizontal; 374eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mRelativeEdges[VERTICAL] = vertical; 375eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 376eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 377eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 378eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 379eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the absolute maximum edge size. 380eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 381eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If relative edge size is not specified, activation edges will always be 382eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the maximum edge size. If both relative and maximum edges are specified, 383eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the maximum edge will be used to constrain the calculated relative edge 384eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * size. 385eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 386eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontalMax The maximum horizontal edge size in pixels, or 387eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MAX} to use the unconstrained calculated relative 388eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * value. 389eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param verticalMax The maximum vertical edge size in pixels, or 390eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MAX} to use the unconstrained calculated relative 391eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * value. 392eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 393eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 394eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setMaximumEdges(float horizontalMax, float verticalMax) { 395eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMaximumEdges[HORIZONTAL] = horizontalMax; 396eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMaximumEdges[VERTICAL] = verticalMax; 397eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 398eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 399eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 400eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 401eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the delay after entering an activation edge before activation of 402eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * auto-scrolling. By default, the activation delay is set to 403eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link ViewConfiguration#getTapTimeout()}. 404eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 405eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Specifying a delay of zero will start auto-scrolling immediately after 406eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the touch position enters an activation edge. 407eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 408eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param delayMillis The activation delay in milliseconds. 409eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 410eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 411eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setActivationDelay(int delayMillis) { 412eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mActivationDelay = delayMillis; 413eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 414eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 415eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 416eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 417eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the amount of time after activation of auto-scrolling that is takes 418eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * to reach target velocity for the current touch position. 419eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 420eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Specifying a duration greater than zero prevents sudden jumps in 421eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * velocity. 422eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 423eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param durationMillis The ramp-up duration in milliseconds. 424eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 425eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 426eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setRampUpDuration(int durationMillis) { 427504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mScroller.setRampUpDuration(durationMillis); 428504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return this; 429504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 430504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 431504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 432504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Sets the amount of time after de-activation of auto-scrolling that is 433504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * takes to slow to a stop. 434504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * <p> 435504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Specifying a duration greater than zero prevents sudden jumps in 436504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * velocity. 437504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * 438504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param durationMillis The ramp-down duration in milliseconds. 439504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return The scroll helper, which may used to chain setter calls. 440504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 441504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public AutoScrollHelper setRampDownDuration(int durationMillis) { 442504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mScroller.setRampDownDuration(durationMillis); 443eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 444eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 445eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 446eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 447eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Handles touch events by activating automatic scrolling, adjusting scroll 4486cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * velocity, or stopping. 4496cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * <p> 450504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * If {@link #isExclusive()} is false, always returns false so that 4516cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * the host view may handle touch events. Otherwise, returns true when 4526cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * automatic scrolling is active and false otherwise. 453eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 454eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette @Override 455eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public boolean onTouch(View v, MotionEvent event) { 456eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (!mEnabled) { 457eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return false; 458eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 459eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 460eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int action = MotionEventCompat.getActionMasked(event); 461eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette switch (action) { 462eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case MotionEvent.ACTION_DOWN: 463504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mNeedsCancel = true; 464504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAlreadyDelayed = false; 465504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // $FALL-THROUGH$ 466eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case MotionEvent.ACTION_MOVE: 467504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float xTargetVelocity = computeTargetVelocity( 468504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette HORIZONTAL, event.getX(), v.getWidth(), mTarget.getWidth()); 469504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float yTargetVelocity = computeTargetVelocity( 470504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette VERTICAL, event.getY(), v.getHeight(), mTarget.getHeight()); 471504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mScroller.setTargetVelocity(xTargetVelocity, yTargetVelocity); 472504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 473504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // If the auto scroller was not previously active, but it should 474504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // be, then update the state and start animations. 475504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (!mAnimating && shouldAnimate()) { 476504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette startAnimating(); 477eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 478eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette break; 479eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case MotionEvent.ACTION_UP: 480eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case MotionEvent.ACTION_CANCEL: 481504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette requestStop(); 482eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette break; 483eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 484eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 485504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return mExclusive && mAnimating; 486eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 487eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 488eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 489504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return whether the target is able to scroll in the requested direction 490504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 491504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private boolean shouldAnimate() { 492504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final ClampedScroller scroller = mScroller; 493504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final int verticalDirection = scroller.getVerticalDirection(); 494504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final int horizontalDirection = scroller.getHorizontalDirection(); 495504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 496504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return verticalDirection != 0 && canTargetScrollVertically(verticalDirection) 497504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette || horizontalDirection != 0 && canTargetScrollHorizontally(horizontalDirection); 498504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 499504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 500504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 501504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Starts the scroll animation. 502504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 503504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private void startAnimating() { 504504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mRunnable == null) { 505504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mRunnable = new ScrollAnimationRunnable(); 506504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 507504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 508504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAnimating = true; 509504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mNeedsReset = true; 510504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 511504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (!mAlreadyDelayed && mActivationDelay > 0) { 512504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette ViewCompat.postOnAnimationDelayed(mTarget, mRunnable, mActivationDelay); 513504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 514504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mRunnable.run(); 515504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 516504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 517504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // If we start animating again before the user lifts their finger, we 518504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // already know it's not a tap and don't need an activation delay. 519504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAlreadyDelayed = true; 520504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 521504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 522504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 523504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Requests that the scroll animation slow to a stop. If there is an 524504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * activation delay, this may occur between posting the animation and 525504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * actually running it. 526504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 527504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private void requestStop() { 528504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mNeedsReset) { 529504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // The animation has been posted, but hasn't run yet. Manually 530504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // stopping animation will prevent it from running. 531504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAnimating = false; 532504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 533504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mScroller.requestStop(); 534504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 535504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 536504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 537504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private float computeTargetVelocity( 538504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette int direction, float coordinate, float srcSize, float dstSize) { 539504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float relativeEdge = mRelativeEdges[direction]; 540504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float maximumEdge = mMaximumEdges[direction]; 541504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float value = getEdgeValue(relativeEdge, srcSize, maximumEdge, coordinate); 542504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (value == 0) { 543504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // The edge in this direction is not activated. 544504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return 0; 545504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 546504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 547504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float relativeVelocity = mRelativeVelocity[direction]; 548504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float minimumVelocity = mMinimumVelocity[direction]; 549504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float maximumVelocity = mMaximumVelocity[direction]; 550504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float targetVelocity = relativeVelocity * dstSize; 551504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 552504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // Target velocity is adjusted for interpolated edge position, then 553504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // clamped to the minimum and maximum values. Later, this value will be 554504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // adjusted for time-based acceleration. 555504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (value > 0) { 556504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return constrain(value * targetVelocity, minimumVelocity, maximumVelocity); 557504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 558504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return -constrain(-value * targetVelocity, minimumVelocity, maximumVelocity); 559504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 560504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 561504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 562504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 563504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Override this method to scroll the target view by the specified number of 564504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * pixels. 565504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * 566504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param deltaX The number of pixels to scroll by horizontally. 567504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param deltaY The number of pixels to scroll by vertically. 568504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 569504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public abstract void scrollTargetBy(int deltaX, int deltaY); 570504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 571504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 572504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Override this method to return whether the target view can be scrolled 573504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * horizontally in a certain direction. 574504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * 575504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param direction Negative to check scrolling left, positive to check 576504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * scrolling right. 577504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return true if the target view is able to horizontally scroll in the 578504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * specified direction. 579504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 580504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public abstract boolean canTargetScrollHorizontally(int direction); 581504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 582504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 583504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Override this method to return whether the target view can be scrolled 584504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * vertically in a certain direction. 585eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 586504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param direction Negative to check scrolling up, positive to check 587504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * scrolling down. 588504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return true if the target view is able to vertically scroll in the 589504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * specified direction. 590eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 591504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public abstract boolean canTargetScrollVertically(int direction); 592eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 593eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 594eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Returns the interpolated position of a touch point relative to an edge 595eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * defined by its relative inset, its maximum absolute inset, and the edge 596eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * interpolator. 597eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 598eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param relativeValue The size of the inset relative to the total size. 599eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param size Total size. 600eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param maxValue The maximum size of the inset, used to clamp (relative * 601eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * total). 602eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param current Touch position within within the total size. 603eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return Interpolated value of the touch position within the edge. 604eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 605eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float getEdgeValue(float relativeValue, float size, float maxValue, float current) { 606eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // For now, leading and trailing edges are always the same size. 607eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float edgeSize = constrain(relativeValue * size, NO_MIN, maxValue); 608eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float valueLeading = constrainEdgeValue(current, edgeSize); 609eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float valueTrailing = constrainEdgeValue(size - current, edgeSize); 610eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float value = (valueTrailing - valueLeading); 611eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float interpolated; 612eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (value < 0) { 613eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette interpolated = -mEdgeInterpolator.getInterpolation(-value); 614eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } else if (value > 0) { 615eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette interpolated = mEdgeInterpolator.getInterpolation(value); 616eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } else { 617eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 0; 618eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 619eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 620eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return constrain(interpolated, -1, 1); 621eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 622eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 623eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float constrainEdgeValue(float current, float leading) { 624eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (leading == 0) { 625eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 0; 626eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 627eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 628eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette switch (mEdgeType) { 629eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case EDGE_TYPE_INSIDE: 630eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case EDGE_TYPE_INSIDE_EXTEND: 631eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (current < leading) { 6327b1a5a45acedd56616807d5c4b3acc17fbfc92adMindy Pereira if (current >= 0) { 633eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // Movement up to the edge is scaled. 634eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 1f - current / leading; 635504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else if (mAnimating && (mEdgeType == EDGE_TYPE_INSIDE_EXTEND)) { 636eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // Movement beyond the edge is always maximum. 637eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 1f; 638eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 639eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 640eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette break; 641eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case EDGE_TYPE_OUTSIDE: 642eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (current < 0) { 643eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // Movement beyond the edge is scaled. 644eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return current / -leading; 645eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 646eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette break; 647eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 648eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 649eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 0; 650eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 651eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 652504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private static int constrain(int value, int min, int max) { 653eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (value > max) { 654eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return max; 655eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } else if (value < min) { 656eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return min; 657eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } else { 658eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return value; 659eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 660eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 661eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 662504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private static float constrain(float value, float min, float max) { 663504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (value > max) { 664504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return max; 665504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else if (value < min) { 666504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return min; 667504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 668504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return value; 669eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 670eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 671eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 6726cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette /** 6736cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * Sends a {@link MotionEvent#ACTION_CANCEL} event to the target view, 6746cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * canceling any ongoing touch events. 6756cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette */ 6766cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette private void cancelTargetTouch() { 677504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long eventTime = SystemClock.uptimeMillis(); 6786cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette final MotionEvent cancel = MotionEvent.obtain( 679504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette eventTime, eventTime, MotionEvent.ACTION_CANCEL, 0, 0, 0); 6806cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette mTarget.onTouchEvent(cancel); 6816cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette cancel.recycle(); 6826cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette } 6836cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 684504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private class ScrollAnimationRunnable implements Runnable { 685eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette @Override 686eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public void run() { 687504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (!mAnimating) { 688eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return; 689eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 690eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 691504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mNeedsReset) { 692504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mNeedsReset = false; 693eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mScroller.start(); 694eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 695eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 696eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final ClampedScroller scroller = mScroller; 697504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (scroller.isFinished() || !shouldAnimate()) { 698504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAnimating = false; 699504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return; 700504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 701504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 702504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mNeedsCancel) { 703504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mNeedsCancel = false; 704504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette cancelTargetTouch(); 705504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 706504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 707eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette scroller.computeScrollDelta(); 708eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 709eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int deltaX = scroller.getDeltaX(); 710eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int deltaY = scroller.getDeltaY(); 711504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette scrollTargetBy(deltaX, deltaY); 7126cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 713504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // Keep going until the scroller has permanently stopped. 714504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette ViewCompat.postOnAnimation(mTarget, this); 715eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 716eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 717eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 718eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 719eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Scroller whose velocity follows the curve of an {@link Interpolator} and 720eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * is clamped to the interpolated 0f value before starting and the 721eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * interpolated 1f value after a specified duration. 722eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 723eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static class ClampedScroller { 724504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private int mRampUpDuration; 725504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private int mRampDownDuration; 726eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float mTargetVelocityX; 727eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float mTargetVelocityY; 728eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 729eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private long mStartTime; 730504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 731eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private long mDeltaTime; 732eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private int mDeltaX; 733eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private int mDeltaY; 734eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 735504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private long mStopTime; 736504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private float mStopValue; 737504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private int mEffectiveRampDown; 738504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 739eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 740eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Creates a new ramp-up scroller that reaches full velocity after a 741eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * specified duration. 742eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 743eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public ClampedScroller() { 744504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStartTime = Long.MIN_VALUE; 745504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopTime = -1; 746504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaTime = 0; 747504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaX = 0; 748504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaY = 0; 749eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 750eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 751504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public void setRampUpDuration(int durationMillis) { 752504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mRampUpDuration = durationMillis; 753504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 754504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 755504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public void setRampDownDuration(int durationMillis) { 756504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mRampDownDuration = durationMillis; 757eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 758eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 759eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 760eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Starts the scroller at the current animation time. 761eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 762eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public void start() { 763eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mStartTime = AnimationUtils.currentAnimationTimeMillis(); 764504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopTime = -1; 765eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mDeltaTime = mStartTime; 766504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopValue = 0.5f; 767504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaX = 0; 768504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaY = 0; 769eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 770eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 771eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 772504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Stops the scroller at the current animation time. 773eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 774504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public void requestStop() { 775504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long currentTime = AnimationUtils.currentAnimationTimeMillis(); 776504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mEffectiveRampDown = constrain((int) (currentTime - mStartTime), 0, mRampDownDuration); 777504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopValue = getValueAt(currentTime); 778504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopTime = currentTime; 779504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 780504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 781eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public boolean isFinished() { 782504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return mStopTime > 0 783504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette && AnimationUtils.currentAnimationTimeMillis() > mStopTime + mEffectiveRampDown; 784504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 785504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 786504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private float getValueAt(long currentTime) { 787504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (currentTime < mStartTime) { 788504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return 0f; 789504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else if (mStopTime < 0 || currentTime < mStopTime) { 790504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long elapsedSinceStart = currentTime - mStartTime; 791504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return 0.5f * constrain(elapsedSinceStart / (float) mRampUpDuration, 0, 1); 792504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 793504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long elapsedSinceEnd = currentTime - mStopTime; 794504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return (1 - mStopValue) + mStopValue 795504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * constrain(elapsedSinceEnd / (float) mEffectiveRampDown, 0, 1); 796eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 797eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 798eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 799eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 800504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Interpolates the value along a parabolic curve corresponding to the equation 801504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * <code>y = -4x * (x-1)</code>. 802504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * 803504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param value The value to interpolate, between 0 and 1. 804504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return the interpolated value, between 0 and 1. 805eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 806504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private float interpolateValue(float value) { 807504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return -4 * value * value + 4 * value; 808eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 809eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 810eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 811eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Computes the current scroll deltas. This usually only be called after 812eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * starting the scroller with {@link #start()}. 813eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 814eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #getDeltaX() 815eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #getDeltaY() 816eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 817eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public void computeScrollDelta() { 818504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mDeltaTime == 0) { 819504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette throw new RuntimeException("Cannot compute scroll delta before calling start()"); 820eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 821eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 822504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long currentTime = AnimationUtils.currentAnimationTimeMillis(); 823504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float value = getValueAt(currentTime); 824504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float scale = interpolateValue(value); 825eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final long elapsedSinceDelta = currentTime - mDeltaTime; 826eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 827eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mDeltaTime = currentTime; 828eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mDeltaX = (int) (elapsedSinceDelta * scale * mTargetVelocityX); 829eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mDeltaY = (int) (elapsedSinceDelta * scale * mTargetVelocityY); 830eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 831eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 832eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 833eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the target velocity for this scroller. 834eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 835eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param x The target X velocity in pixels per millisecond. 836eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param y The target Y velocity in pixels per millisecond. 837eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 838eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public void setTargetVelocity(float x, float y) { 839eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mTargetVelocityX = x; 840eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mTargetVelocityY = y; 841eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 842eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 843504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public int getHorizontalDirection() { 844504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return (int) (mTargetVelocityX / Math.abs(mTargetVelocityX)); 845504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 846504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 847504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public int getVerticalDirection() { 848504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return (int) (mTargetVelocityY / Math.abs(mTargetVelocityY)); 849504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 850504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 851eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 852eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The distance traveled in the X-coordinate computed by the last call 853eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * to {@link #computeScrollDelta()}. 854eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 855eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public int getDeltaX() { 856eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return mDeltaX; 857eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 858eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 859eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 860eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The distance traveled in the Y-coordinate computed by the last call 861eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * to {@link #computeScrollDelta()}. 862eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 863eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public int getDeltaY() { 864eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return mDeltaY; 865eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 866eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 867eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette} 868