AutoScrollHelper.java revision b78985701876dc678d982bf4f838f40a806f72a9
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.ViewCompat; 22eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.util.DisplayMetrics; 23eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.MotionEvent; 24eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.View; 25eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.ViewConfiguration; 26eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.animation.AccelerateInterpolator; 27eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.animation.AnimationUtils; 28eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viveretteimport android.view.animation.Interpolator; 29eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 30eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette/** 31eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * AutoScrollHelper is a utility class for adding automatic edge-triggered 32eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * scrolling to Views. 33eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 34eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <b>Note:</b> Implementing classes are responsible for overriding the 35504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * {@link #scrollTargetBy}, {@link #canTargetScrollHorizontally}, and 36504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * {@link #canTargetScrollVertically} methods. See 37eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link ListViewAutoScrollHelper} for a {@link android.widget.ListView} 38eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * -specific implementation. 39eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 40eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <h1>Activation</h1> Automatic scrolling starts when the user touches within 41eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * an activation area. By default, activation areas are defined as the top, 42eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * left, right, and bottom 20% of the host view's total area. Touching within 43eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the top activation area scrolls up, left scrolls to the left, and so on. 44eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 45eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * As the user touches closer to the extreme edge of the activation area, 46eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * scrolling accelerates up to a maximum velocity. When using the default edge 47eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * type, {@link #EDGE_TYPE_INSIDE_EXTEND}, moving outside of the view bounds 48eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * will scroll at the maximum velocity. 49eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 50eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The following activation properties may be configured: 51eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <ul> 52eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Delay after entering activation area before auto-scrolling begins, see 53eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setActivationDelay}. Default value is 54eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link ViewConfiguration#getTapTimeout()} to avoid conflicting with taps. 55eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Location of activation areas, see {@link #setEdgeType}. Default value is 56eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #EDGE_TYPE_INSIDE_EXTEND}. 57eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Size of activation areas relative to view size, see 58eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setRelativeEdges}. Default value is 20% for both vertical and 59eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * horizontal edges. 60eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Maximum size used to constrain relative size, see 61eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setMaximumEdges}. Default value is {@link #NO_MAX}. 62eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * </ul> 63eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <h1>Scrolling</h1> When automatic scrolling is active, the helper will 64504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * repeatedly call {@link #scrollTargetBy} to apply new scrolling offsets. 65eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 66eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The following scrolling properties may be configured: 67eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <ul> 68eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Acceleration ramp-up duration, see {@link #setRampUpDuration}. Default 692155135a266e288854714775d8a9ba7d8eddfd2aMindy Pereira * value is 500 milliseconds. 70504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * <li>Acceleration ramp-down duration, see {@link #setRampDownDuration}. 71504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Default value is 500 milliseconds. 72eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Target velocity relative to view size, see {@link #setRelativeVelocity}. 73eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Default value is 100% per second for both vertical and horizontal. 74eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Minimum velocity used to constrain relative velocity, see 75eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setMinimumVelocity}. When set, scrolling will accelerate to the 76eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * larger of either this value or the relative target value. Default value is 77eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * approximately 5 centimeters or 315 dips per second. 78eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>Maximum velocity used to constrain relative velocity, see 79eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setMaximumVelocity}. Default value is approximately 25 centimeters or 80eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 1575 dips per second. 81eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * </ul> 82eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 83eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverettepublic abstract class AutoScrollHelper implements View.OnTouchListener { 84eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 85eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Constant passed to {@link #setRelativeEdges} or 86eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setRelativeVelocity}. Using this value ensures that the computed 87eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * relative value is ignored and the absolute maximum value is always used. 88eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 89eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final float RELATIVE_UNSPECIFIED = 0; 90eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 91eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 92eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Constant passed to {@link #setMaximumEdges}, {@link #setMaximumVelocity}, 93eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * or {@link #setMinimumVelocity}. Using this value ensures that the 94eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * computed relative value is always used without constraining to a 95eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * particular minimum or maximum value. 96eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 97eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final float NO_MAX = Float.MAX_VALUE; 98eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 99eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 100eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Constant passed to {@link #setMaximumEdges}, or 101eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #setMaximumVelocity}, or {@link #setMinimumVelocity}. Using this 102eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * value ensures that the computed relative value is always used without 103eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * constraining to a particular minimum or maximum value. 104eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 105eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final float NO_MIN = 0; 106eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 107eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 108eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Edge type that specifies an activation area starting at the view bounds 109eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * and extending inward. Moving outside the view bounds will stop scrolling. 110eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 111eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #setEdgeType 112eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 113eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final int EDGE_TYPE_INSIDE = 0; 114eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 115eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 116eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Edge type that specifies an activation area starting at the view bounds 117eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * and extending inward. After activation begins, moving outside the view 118eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * bounds will continue scrolling. 119eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 120eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #setEdgeType 121eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 122eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final int EDGE_TYPE_INSIDE_EXTEND = 1; 123eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 124eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 125eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Edge type that specifies an activation area starting at the view bounds 126eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * and extending outward. Moving inside the view bounds will stop scrolling. 127eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 128eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #setEdgeType 129eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 130eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public static final int EDGE_TYPE_OUTSIDE = 2; 131eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 132eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int HORIZONTAL = 0; 133eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int VERTICAL = 1; 134eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 135eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Scroller used to control acceleration toward maximum velocity. */ 136540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas final ClampedScroller mScroller = new ClampedScroller(); 137eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 138eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Interpolator used to scale velocity with touch position. */ 139eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private final Interpolator mEdgeInterpolator = new AccelerateInterpolator(); 140eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 141eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** The view to auto-scroll. Might not be the source of touch events. */ 142540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas final View mTarget; 143eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 144eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Runnable used to animate scrolling. */ 145eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private Runnable mRunnable; 146eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 147eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Edge insets used to activate auto-scrolling. */ 148eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mRelativeEdges = new float[] { RELATIVE_UNSPECIFIED, RELATIVE_UNSPECIFIED }; 149eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 150eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Clamping values for edge insets used to activate auto-scrolling. */ 151eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mMaximumEdges = new float[] { NO_MAX, NO_MAX }; 152eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 153eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** The type of edge being used. */ 154eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private int mEdgeType; 155eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 156eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Delay after entering an activation edge before auto-scrolling begins. */ 157eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private int mActivationDelay; 158eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 159eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Relative scrolling velocity at maximum edge distance. */ 160eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mRelativeVelocity = new float[] { RELATIVE_UNSPECIFIED, RELATIVE_UNSPECIFIED }; 161eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 162eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Clamping values used for scrolling velocity. */ 163eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mMinimumVelocity = new float[] { NO_MIN, NO_MIN }; 164eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 165eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Clamping values used for scrolling velocity. */ 166eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float[] mMaximumVelocity = new float[] { NO_MAX, NO_MAX }; 167eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 168eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Whether to start activation immediately. */ 169504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private boolean mAlreadyDelayed; 170eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 171eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Whether to reset the scroller start time on the next animation. */ 172540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas boolean mNeedsReset; 173eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 174504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** Whether to send a cancel motion event to the target view. */ 175540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas boolean mNeedsCancel; 176eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 177504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** Whether the auto-scroller is actively scrolling. */ 178540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas boolean mAnimating; 1796cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 180eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** Whether the auto-scroller is enabled. */ 181eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private boolean mEnabled; 182eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 1836cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette /** Whether the auto-scroller consumes events when scrolling. */ 184504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private boolean mExclusive; 1856cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 186eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // Default values. 187eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int DEFAULT_EDGE_TYPE = EDGE_TYPE_INSIDE_EXTEND; 188eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int DEFAULT_MINIMUM_VELOCITY_DIPS = 315; 189eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int DEFAULT_MAXIMUM_VELOCITY_DIPS = 1575; 190eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final float DEFAULT_MAXIMUM_EDGE = NO_MAX; 191eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final float DEFAULT_RELATIVE_EDGE = 0.2f; 192eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final float DEFAULT_RELATIVE_VELOCITY = 1f; 193eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static final int DEFAULT_ACTIVATION_DELAY = ViewConfiguration.getTapTimeout(); 1942155135a266e288854714775d8a9ba7d8eddfd2aMindy Pereira private static final int DEFAULT_RAMP_UP_DURATION = 500; 195504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private static final int DEFAULT_RAMP_DOWN_DURATION = 500; 196eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 197eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 198eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Creates a new helper for scrolling the specified target view. 199eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 200eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The resulting helper may be configured by chaining setter calls and 201eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * should be set as a touch listener on the target view. 202eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 203eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * By default, the helper is disabled and will not respond to touch events 204eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * until it is enabled using {@link #setEnabled}. 205eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 206eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param target The view to automatically scroll. 207eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 208eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper(View target) { 209eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mTarget = target; 210eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 211eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); 212eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int maxVelocity = (int) (DEFAULT_MAXIMUM_VELOCITY_DIPS * metrics.density + 0.5f); 213eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int minVelocity = (int) (DEFAULT_MINIMUM_VELOCITY_DIPS * metrics.density + 0.5f); 214eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setMaximumVelocity(maxVelocity, maxVelocity); 215eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setMinimumVelocity(minVelocity, minVelocity); 216eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 217eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setEdgeType(DEFAULT_EDGE_TYPE); 218eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setMaximumEdges(DEFAULT_MAXIMUM_EDGE, DEFAULT_MAXIMUM_EDGE); 219eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setRelativeEdges(DEFAULT_RELATIVE_EDGE, DEFAULT_RELATIVE_EDGE); 220eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setRelativeVelocity(DEFAULT_RELATIVE_VELOCITY, DEFAULT_RELATIVE_VELOCITY); 221eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setActivationDelay(DEFAULT_ACTIVATION_DELAY); 222eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette setRampUpDuration(DEFAULT_RAMP_UP_DURATION); 223504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette setRampDownDuration(DEFAULT_RAMP_DOWN_DURATION); 224eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 225eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 226eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 227eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets whether the scroll helper is enabled and should respond to touch 228eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * events. 229eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 230eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param enabled Whether the scroll helper is enabled. 231eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 232eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 233eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setEnabled(boolean enabled) { 234504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mEnabled && !enabled) { 235504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette requestStop(); 236eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 237eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 238eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mEnabled = enabled; 239eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 240eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 241eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 242eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 243eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return True if this helper is enabled and responding to touch events. 244eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 245eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public boolean isEnabled() { 246eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return mEnabled; 247eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 248eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 249eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 2506cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * Enables or disables exclusive handling of touch events during scrolling. 2516cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * By default, exclusive handling is disabled and the target view receives 2526cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * all touch events. 2536cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * <p> 2546cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * When enabled, {@link #onTouch} will return true if the helper is 2556cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * currently scrolling and false otherwise. 2566cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * 257504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param exclusive True to exclusively handle touch events during scrolling, 2586cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * false to allow the target view to receive all touch events. 259504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return The scroll helper, which may used to chain setter calls. 2606cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette */ 261504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public AutoScrollHelper setExclusive(boolean exclusive) { 262504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mExclusive = exclusive; 263504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return this; 2646cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette } 2656cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 2666cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette /** 2676cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * Indicates whether the scroll helper handles touch events exclusively 2686cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * during scrolling. 2696cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * 2706cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * @return True if exclusive handling of touch events during scrolling is 2716cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * enabled, false otherwise. 272504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @see #setExclusive(boolean) 2736cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette */ 274504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public boolean isExclusive() { 275504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return mExclusive; 2766cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette } 2776cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 2786cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette /** 279eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the absolute maximum scrolling velocity. 280eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 281eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If relative velocity is not specified, scrolling will always reach the 282eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * same maximum velocity. If both relative and maximum velocities are 283eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * specified, the maximum velocity will be used to clamp the calculated 284eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * relative velocity. 285eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 286eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontalMax The maximum horizontal scrolling velocity, or 287eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MAX} to leave the relative value unconstrained. 288eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param verticalMax The maximum vertical scrolling velocity, or 289eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MAX} to leave the relative value unconstrained. 290eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 291eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 292eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setMaximumVelocity(float horizontalMax, float verticalMax) { 293eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMaximumVelocity[HORIZONTAL] = horizontalMax / 1000f; 294eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMaximumVelocity[VERTICAL] = verticalMax / 1000f; 295eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 296eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 297eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 298eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 299eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the absolute minimum scrolling velocity. 300eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 301eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If both relative and minimum velocities are specified, the minimum 302eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * velocity will be used to clamp the calculated relative velocity. 303eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 304eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontalMin The minimum horizontal scrolling velocity, or 305eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MIN} to leave the relative value unconstrained. 306eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param verticalMin The minimum vertical scrolling velocity, or 307eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MIN} to leave the relative value unconstrained. 308eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 309eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 310eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setMinimumVelocity(float horizontalMin, float verticalMin) { 311eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMinimumVelocity[HORIZONTAL] = horizontalMin / 1000f; 312eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMinimumVelocity[VERTICAL] = verticalMin / 1000f; 313eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 314eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 315eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 316eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 317eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the target scrolling velocity relative to the host view's 318eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * dimensions. 319eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 320eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If both relative and maximum velocities are specified, the maximum 321eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * velocity will be used to clamp the calculated relative velocity. 322eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 323eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontal The target horizontal velocity as a fraction of the 324eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * host view width per second, or {@link #RELATIVE_UNSPECIFIED} 325eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * to ignore. 326eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param vertical The target vertical velocity as a fraction of the host 327eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * view height per second, or {@link #RELATIVE_UNSPECIFIED} to 328eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * ignore. 329eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 330eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 331eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setRelativeVelocity(float horizontal, float vertical) { 332eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mRelativeVelocity[HORIZONTAL] = horizontal / 1000f; 333eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mRelativeVelocity[VERTICAL] = vertical / 1000f; 334eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 335eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 336eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 337eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 338eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the activation edge type, one of: 339eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <ul> 340eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>{@link #EDGE_TYPE_INSIDE} for edges that respond to touches inside 341eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the bounds of the host view. If touch moves outside the bounds, scrolling 342eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * will stop. 343eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>{@link #EDGE_TYPE_INSIDE_EXTEND} for inside edges that continued to 344eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * scroll when touch moves outside the bounds of the host view. 345eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <li>{@link #EDGE_TYPE_OUTSIDE} for edges that only respond to touches 346eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * that move outside the bounds of the host view. 347eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * </ul> 348eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 349eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param type The type of edge to use. 350eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 351eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 352eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setEdgeType(int type) { 353eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mEdgeType = type; 354eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 355eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 356eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 357eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 358eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the activation edge size relative to the host view's dimensions. 359eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 360eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If both relative and maximum edges are specified, the maximum edge will 361eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * be used to constrain the calculated relative edge size. 362eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 363eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontal The horizontal edge size as a fraction of the host view 364eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * width, or {@link #RELATIVE_UNSPECIFIED} to always use the 365eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * maximum value. 366eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param vertical The vertical edge size as a fraction of the host view 367eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * height, or {@link #RELATIVE_UNSPECIFIED} to always use the 368eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * maximum value. 369eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 370eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 371eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setRelativeEdges(float horizontal, float vertical) { 372eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mRelativeEdges[HORIZONTAL] = horizontal; 373eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mRelativeEdges[VERTICAL] = vertical; 374eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 375eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 376eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 377eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 378eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the absolute maximum edge size. 379eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 380eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * If relative edge size is not specified, activation edges will always be 381eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the maximum edge size. If both relative and maximum edges are specified, 382eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the maximum edge will be used to constrain the calculated relative edge 383eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * size. 384eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 385eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param horizontalMax The maximum horizontal edge size in pixels, or 386eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MAX} to use the unconstrained calculated relative 387eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * value. 388eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param verticalMax The maximum vertical edge size in pixels, or 389eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link #NO_MAX} to use the unconstrained calculated relative 390eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * value. 391eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 392eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 393eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setMaximumEdges(float horizontalMax, float verticalMax) { 394eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMaximumEdges[HORIZONTAL] = horizontalMax; 395eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mMaximumEdges[VERTICAL] = verticalMax; 396eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 397eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 398eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 399eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 400eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the delay after entering an activation edge before activation of 401eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * auto-scrolling. By default, the activation delay is set to 402eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * {@link ViewConfiguration#getTapTimeout()}. 403eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 404eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Specifying a delay of zero will start auto-scrolling immediately after 405eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * the touch position enters an activation edge. 406eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 407eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param delayMillis The activation delay in milliseconds. 408eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 409eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 410eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setActivationDelay(int delayMillis) { 411eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mActivationDelay = delayMillis; 412eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 413eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 414eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 415eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 416eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the amount of time after activation of auto-scrolling that is takes 417eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * to reach target velocity for the current touch position. 418eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * <p> 419eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Specifying a duration greater than zero prevents sudden jumps in 420eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * velocity. 421eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 422eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param durationMillis The ramp-up duration in milliseconds. 423eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return The scroll helper, which may used to chain setter calls. 424eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 425eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public AutoScrollHelper setRampUpDuration(int durationMillis) { 426504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mScroller.setRampUpDuration(durationMillis); 427504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return this; 428504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 429504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 430504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 431504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Sets the amount of time after de-activation of auto-scrolling that is 432504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * takes to slow to a stop. 433504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * <p> 434504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Specifying a duration greater than zero prevents sudden jumps in 435504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * velocity. 436504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * 437504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param durationMillis The ramp-down duration in milliseconds. 438504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return The scroll helper, which may used to chain setter calls. 439504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 440504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public AutoScrollHelper setRampDownDuration(int durationMillis) { 441504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mScroller.setRampDownDuration(durationMillis); 442eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return this; 443eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 444eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 445eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 446eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Handles touch events by activating automatic scrolling, adjusting scroll 4476cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * velocity, or stopping. 4486cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * <p> 449504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * If {@link #isExclusive()} is false, always returns false so that 4506cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * the host view may handle touch events. Otherwise, returns true when 4516cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * automatic scrolling is active and false otherwise. 452eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 453eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette @Override 454eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public boolean onTouch(View v, MotionEvent event) { 455eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (!mEnabled) { 456eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return false; 457eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 458eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 4596ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas final int action = event.getActionMasked(); 460eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette switch (action) { 461eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case MotionEvent.ACTION_DOWN: 462504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mNeedsCancel = true; 463504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAlreadyDelayed = false; 464504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // $FALL-THROUGH$ 465eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case MotionEvent.ACTION_MOVE: 466504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float xTargetVelocity = computeTargetVelocity( 467504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette HORIZONTAL, event.getX(), v.getWidth(), mTarget.getWidth()); 468504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float yTargetVelocity = computeTargetVelocity( 469504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette VERTICAL, event.getY(), v.getHeight(), mTarget.getHeight()); 470504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mScroller.setTargetVelocity(xTargetVelocity, yTargetVelocity); 471504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 472504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // If the auto scroller was not previously active, but it should 473504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // be, then update the state and start animations. 474504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (!mAnimating && shouldAnimate()) { 475504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette startAnimating(); 476eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 477eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette break; 478eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case MotionEvent.ACTION_UP: 479eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case MotionEvent.ACTION_CANCEL: 480504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette requestStop(); 481eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette break; 482eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 483eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 484504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return mExclusive && mAnimating; 485eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 486eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 487eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 488504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return whether the target is able to scroll in the requested direction 489504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 490540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas boolean shouldAnimate() { 491504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final ClampedScroller scroller = mScroller; 492504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final int verticalDirection = scroller.getVerticalDirection(); 493504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final int horizontalDirection = scroller.getHorizontalDirection(); 494504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 495b78985701876dc678d982bf4f838f40a806f72a9Aurimas Liutikas return (verticalDirection != 0 && canTargetScrollVertically(verticalDirection)) 496b78985701876dc678d982bf4f838f40a806f72a9Aurimas Liutikas || (horizontalDirection != 0 && canTargetScrollHorizontally(horizontalDirection)); 497504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 498504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 499504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 500504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Starts the scroll animation. 501504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 502504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private void startAnimating() { 503504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mRunnable == null) { 504504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mRunnable = new ScrollAnimationRunnable(); 505504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 506504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 507504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAnimating = true; 508504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mNeedsReset = true; 509504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 510504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (!mAlreadyDelayed && mActivationDelay > 0) { 511504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette ViewCompat.postOnAnimationDelayed(mTarget, mRunnable, mActivationDelay); 512504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 513504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mRunnable.run(); 514504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 515504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 516504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // If we start animating again before the user lifts their finger, we 517504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // already know it's not a tap and don't need an activation delay. 518504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAlreadyDelayed = true; 519504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 520504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 521504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 522504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Requests that the scroll animation slow to a stop. If there is an 523504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * activation delay, this may occur between posting the animation and 524504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * actually running it. 525504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 526504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private void requestStop() { 527504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mNeedsReset) { 528504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // The animation has been posted, but hasn't run yet. Manually 529504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // stopping animation will prevent it from running. 530504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAnimating = false; 531504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 532504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mScroller.requestStop(); 533504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 534504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 535504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 536504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private float computeTargetVelocity( 537504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette int direction, float coordinate, float srcSize, float dstSize) { 538504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float relativeEdge = mRelativeEdges[direction]; 539504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float maximumEdge = mMaximumEdges[direction]; 540504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float value = getEdgeValue(relativeEdge, srcSize, maximumEdge, coordinate); 541504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (value == 0) { 542504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // The edge in this direction is not activated. 543504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return 0; 544504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 545504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 546504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float relativeVelocity = mRelativeVelocity[direction]; 547504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float minimumVelocity = mMinimumVelocity[direction]; 548504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float maximumVelocity = mMaximumVelocity[direction]; 549504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float targetVelocity = relativeVelocity * dstSize; 550504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 551504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // Target velocity is adjusted for interpolated edge position, then 552504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // clamped to the minimum and maximum values. Later, this value will be 553504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // adjusted for time-based acceleration. 554504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (value > 0) { 555504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return constrain(value * targetVelocity, minimumVelocity, maximumVelocity); 556504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 557504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return -constrain(-value * targetVelocity, minimumVelocity, maximumVelocity); 558504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 559504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 560504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 561504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 562504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Override this method to scroll the target view by the specified number of 563504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * pixels. 564504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * 565504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param deltaX The number of pixels to scroll by horizontally. 566504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param deltaY The number of pixels to scroll by vertically. 567504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 568504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public abstract void scrollTargetBy(int deltaX, int deltaY); 569504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 570504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 571504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Override this method to return whether the target view can be scrolled 572504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * horizontally in a certain direction. 573504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * 574504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param direction Negative to check scrolling left, positive to check 575504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * scrolling right. 576504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return true if the target view is able to horizontally scroll in the 577504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * specified direction. 578504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette */ 579504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public abstract boolean canTargetScrollHorizontally(int direction); 580504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 581504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette /** 582504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Override this method to return whether the target view can be scrolled 583504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * vertically in a certain direction. 584eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 585504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param direction Negative to check scrolling up, positive to check 586504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * scrolling down. 587504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return true if the target view is able to vertically scroll in the 588504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * specified direction. 589eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 590504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public abstract boolean canTargetScrollVertically(int direction); 591eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 592eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 593eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Returns the interpolated position of a touch point relative to an edge 594eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * defined by its relative inset, its maximum absolute inset, and the edge 595eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * interpolator. 596eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 597eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param relativeValue The size of the inset relative to the total size. 598eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param size Total size. 599eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param maxValue The maximum size of the inset, used to clamp (relative * 600eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * total). 601eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param current Touch position within within the total size. 602eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @return Interpolated value of the touch position within the edge. 603eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 604eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float getEdgeValue(float relativeValue, float size, float maxValue, float current) { 605eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // For now, leading and trailing edges are always the same size. 606eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float edgeSize = constrain(relativeValue * size, NO_MIN, maxValue); 607eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float valueLeading = constrainEdgeValue(current, edgeSize); 608eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float valueTrailing = constrainEdgeValue(size - current, edgeSize); 609eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float value = (valueTrailing - valueLeading); 610eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final float interpolated; 611eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (value < 0) { 612eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette interpolated = -mEdgeInterpolator.getInterpolation(-value); 613eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } else if (value > 0) { 614eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette interpolated = mEdgeInterpolator.getInterpolation(value); 615eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } else { 616eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 0; 617eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 618eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 619eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return constrain(interpolated, -1, 1); 620eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 621eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 622eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float constrainEdgeValue(float current, float leading) { 623eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (leading == 0) { 624eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 0; 625eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 626eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 627eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette switch (mEdgeType) { 628eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case EDGE_TYPE_INSIDE: 629eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case EDGE_TYPE_INSIDE_EXTEND: 630eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (current < leading) { 6317b1a5a45acedd56616807d5c4b3acc17fbfc92adMindy Pereira if (current >= 0) { 632eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // Movement up to the edge is scaled. 633eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 1f - current / leading; 634504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else if (mAnimating && (mEdgeType == EDGE_TYPE_INSIDE_EXTEND)) { 635eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // Movement beyond the edge is always maximum. 636eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 1f; 637eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 638eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 639eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette break; 640eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette case EDGE_TYPE_OUTSIDE: 641eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (current < 0) { 642eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette // Movement beyond the edge is scaled. 643eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return current / -leading; 644eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 645eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette break; 646eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 647eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 648eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return 0; 649eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 650eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 651540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas static int constrain(int value, int min, int max) { 652eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette if (value > max) { 653eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return max; 654eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } else if (value < min) { 655eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return min; 656eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } else { 657eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return value; 658eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 659eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 660eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 661540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas static float constrain(float value, float min, float max) { 662504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (value > max) { 663504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return max; 664504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else if (value < min) { 665504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return min; 666504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 667504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return value; 668eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 669eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 670eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 6716cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette /** 6726cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * Sends a {@link MotionEvent#ACTION_CANCEL} event to the target view, 6736cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette * canceling any ongoing touch events. 6746cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette */ 675540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas void cancelTargetTouch() { 676504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long eventTime = SystemClock.uptimeMillis(); 6776cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette final MotionEvent cancel = MotionEvent.obtain( 678504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette eventTime, eventTime, MotionEvent.ACTION_CANCEL, 0, 0, 0); 6796cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette mTarget.onTouchEvent(cancel); 6806cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette cancel.recycle(); 6816cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette } 6826cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 683504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private class ScrollAnimationRunnable implements Runnable { 684540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas ScrollAnimationRunnable() { 685540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas } 686540222c3675801eaa141ace1c164c4d3499b4721Aurimas Liutikas 687eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette @Override 688eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public void run() { 689504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (!mAnimating) { 690eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return; 691eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 692eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 693504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mNeedsReset) { 694504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mNeedsReset = false; 695eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mScroller.start(); 696eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 697eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 698eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final ClampedScroller scroller = mScroller; 699504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (scroller.isFinished() || !shouldAnimate()) { 700504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mAnimating = false; 701504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return; 702504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 703504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 704504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mNeedsCancel) { 705504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mNeedsCancel = false; 706504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette cancelTargetTouch(); 707504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 708504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 709eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette scroller.computeScrollDelta(); 710eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 711eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int deltaX = scroller.getDeltaX(); 712eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final int deltaY = scroller.getDeltaY(); 713504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette scrollTargetBy(deltaX, deltaY); 7146cf8db91596dd60eee4bb90925e4711cebb202d4Alan Viverette 715504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette // Keep going until the scroller has permanently stopped. 716504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette ViewCompat.postOnAnimation(mTarget, this); 717eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 718eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 719eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 720eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 721eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Scroller whose velocity follows the curve of an {@link Interpolator} and 722eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * is clamped to the interpolated 0f value before starting and the 723eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * interpolated 1f value after a specified duration. 724eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 725eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private static class ClampedScroller { 726504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private int mRampUpDuration; 727504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private int mRampDownDuration; 728eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float mTargetVelocityX; 729eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private float mTargetVelocityY; 730eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 731eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private long mStartTime; 732504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 733eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private long mDeltaTime; 734eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private int mDeltaX; 735eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette private int mDeltaY; 736eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 737504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private long mStopTime; 738504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private float mStopValue; 739504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private int mEffectiveRampDown; 740504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 741eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 742eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Creates a new ramp-up scroller that reaches full velocity after a 743eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * specified duration. 744eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 7454d2c7b7c4f194034c5f17c4bee7320d808aabe4cAurimas Liutikas ClampedScroller() { 746504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStartTime = Long.MIN_VALUE; 747504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopTime = -1; 748504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaTime = 0; 749504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaX = 0; 750504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaY = 0; 751eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 752eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 753504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public void setRampUpDuration(int durationMillis) { 754504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mRampUpDuration = durationMillis; 755504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 756504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 757504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public void setRampDownDuration(int durationMillis) { 758504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mRampDownDuration = durationMillis; 759eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 760eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 761eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 762eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Starts the scroller at the current animation time. 763eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 764eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public void start() { 765eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mStartTime = AnimationUtils.currentAnimationTimeMillis(); 766504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopTime = -1; 767eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mDeltaTime = mStartTime; 768504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopValue = 0.5f; 769504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaX = 0; 770504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mDeltaY = 0; 771eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 772eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 773eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 774504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Stops the scroller at the current animation time. 775eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 776504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public void requestStop() { 777504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long currentTime = AnimationUtils.currentAnimationTimeMillis(); 778504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mEffectiveRampDown = constrain((int) (currentTime - mStartTime), 0, mRampDownDuration); 779504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopValue = getValueAt(currentTime); 780504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette mStopTime = currentTime; 781504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 782504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 783eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public boolean isFinished() { 784504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return mStopTime > 0 785504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette && AnimationUtils.currentAnimationTimeMillis() > mStopTime + mEffectiveRampDown; 786504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 787504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 788504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private float getValueAt(long currentTime) { 789504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (currentTime < mStartTime) { 790504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return 0f; 791504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else if (mStopTime < 0 || currentTime < mStopTime) { 792504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long elapsedSinceStart = currentTime - mStartTime; 793504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return 0.5f * constrain(elapsedSinceStart / (float) mRampUpDuration, 0, 1); 794504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } else { 795504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long elapsedSinceEnd = currentTime - mStopTime; 796504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return (1 - mStopValue) + mStopValue 797504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * constrain(elapsedSinceEnd / (float) mEffectiveRampDown, 0, 1); 798eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 799eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 800eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 801eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 802504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * Interpolates the value along a parabolic curve corresponding to the equation 803504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * <code>y = -4x * (x-1)</code>. 804504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * 805504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @param value The value to interpolate, between 0 and 1. 806504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette * @return the interpolated value, between 0 and 1. 807eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 808504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette private float interpolateValue(float value) { 809504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return -4 * value * value + 4 * value; 810eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 811eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 812eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 813eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Computes the current scroll deltas. This usually only be called after 814eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * starting the scroller with {@link #start()}. 815eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 816eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #getDeltaX() 817eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @see #getDeltaY() 818eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 819eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public void computeScrollDelta() { 820504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette if (mDeltaTime == 0) { 821504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette throw new RuntimeException("Cannot compute scroll delta before calling start()"); 822eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 823eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 824504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final long currentTime = AnimationUtils.currentAnimationTimeMillis(); 825504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float value = getValueAt(currentTime); 826504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette final float scale = interpolateValue(value); 827eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette final long elapsedSinceDelta = currentTime - mDeltaTime; 828eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 829eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mDeltaTime = currentTime; 830eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mDeltaX = (int) (elapsedSinceDelta * scale * mTargetVelocityX); 831eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mDeltaY = (int) (elapsedSinceDelta * scale * mTargetVelocityY); 832eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 833eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 834eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 835eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * Sets the target velocity for this scroller. 836eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * 837eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param x The target X velocity in pixels per millisecond. 838eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * @param y The target Y velocity in pixels per millisecond. 839eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 840eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public void setTargetVelocity(float x, float y) { 841eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mTargetVelocityX = x; 842eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette mTargetVelocityY = y; 843eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 844eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 845504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public int getHorizontalDirection() { 846504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return (int) (mTargetVelocityX / Math.abs(mTargetVelocityX)); 847504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 848504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 849504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette public int getVerticalDirection() { 850504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette return (int) (mTargetVelocityY / Math.abs(mTargetVelocityY)); 851504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette } 852504f6b9c6bcc6b2f50b2aaf4cf9b9bcae7e0e755Alan Viverette 853eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 854eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The distance traveled in the X-coordinate computed by the last call 855eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * to {@link #computeScrollDelta()}. 856eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 857eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public int getDeltaX() { 858eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return mDeltaX; 859eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 860eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette 861eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette /** 862eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * The distance traveled in the Y-coordinate computed by the last call 863eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette * to {@link #computeScrollDelta()}. 864eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette */ 865eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette public int getDeltaY() { 866eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette return mDeltaY; 867eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 868eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette } 869eb38a77f4c2b50da454ce0720ceb056f4932f4aeAlan Viverette} 870