&& repo sync -j8 | 518edbf | 2012-11-30 16:28:27 -0800 | [diff] [blame^] | 1 | page.title=Animating a Scroll Gesture |
| 2 | parent.title=Using Touch Gestures |
| 3 | parent.link=index.html |
| 4 | |
| 5 | trainingnavtop=true |
| 6 | next.title=Handling Multi-Touch Gestures |
| 7 | next.link=multi.html |
| 8 | |
| 9 | @jd:body |
| 10 | |
| 11 | <div id="tb-wrapper"> |
| 12 | <div id="tb"> |
| 13 | |
| 14 | <!-- table of contents --> |
| 15 | <h2>This lesson teaches you to</h2> |
| 16 | <ol> |
| 17 | <li><a href="#scroll">Implement Touch-Based Scrolling</a></li> |
| 18 | </ol> |
| 19 | |
| 20 | <!-- other docs (NOT javadocs) --> |
| 21 | <h2>You should also read</h2> |
| 22 | |
| 23 | <ul> |
| 24 | <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide |
| 25 | </li> |
| 26 | <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li> |
| 27 | <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li> |
| 28 | <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li> |
| 29 | <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li> |
| 30 | <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li> |
| 31 | </ul> |
| 32 | |
| 33 | |
| 34 | </div> |
| 35 | </div> |
| 36 | |
| 37 | <p>In Android, scrolling is typically achieved by using the |
| 38 | {@link android.widget.ScrollView} |
| 39 | class. Any standard layout that might extend beyond the bounds of its container should be |
| 40 | nested in a {@link android.widget.ScrollView} to provide a scrollable view that's |
| 41 | managed by the framework. Implementing a custom scroller should only be |
| 42 | necessary for special scenarios. This lesson describes such a scenario: displaying |
| 43 | a scrolling effect in response to touch gestures using <em>scrollers</em>. |
| 44 | |
| 45 | |
| 46 | <p>You can use scrollers ({@link android.widget.Scroller} or {@link |
| 47 | android.widget.OverScroller}) to collect the data you need to produce a |
| 48 | scrolling animation in response to a touch event. {@link |
| 49 | android.widget.Scroller} and {@link android.widget.OverScroller} are largely |
| 50 | interchangeable—the difference is that {@link android.widget.OverScroller} |
| 51 | allows temporarily scrolling beyond the minimum/maximum boundaries and springing |
| 52 | back to the bounds. This is normally rendered using a "glow" effect, provided by |
| 53 | the {@link android.widget.EdgeEffect} or {@link |
| 54 | android.support.v4.widget.EdgeEffectCompat} classes. </p> |
| 55 | |
| 56 | <p>A scroller is used to animate scrolling over time, using platform-standard |
| 57 | scrolling physics (friction, velocity, etc.). The scroller itself doesn't |
| 58 | actually draw anything. Scrollers track scroll offsets for you over time, but |
| 59 | they don't automatically apply those positions to your view. It's your |
| 60 | responsibility to get and apply new coordinates at a rate that will make the |
| 61 | scrolling animation look smooth.</p> |
| 62 | |
| 63 | <p class="note"><strong>Note:</strong> You generally only need to use scrollers |
| 64 | when implementing scrolling yourself. {@link android.widget.ScrollView} and |
| 65 | {@link android.widget.HorizontalScrollView} do all this for you do all of this for you if you nest your layout within them.</p> |
| 66 | |
| 67 | <h2 id = "scroll">Implement Touch-Based Scrolling</h2> |
| 68 | |
| 69 | |
| 70 | <p>This snippet illustrates the basics of using a scroller. It uses a |
| 71 | {@link android.view.GestureDetector}, and overrides the |
| 72 | {@link android.view.GestureDetector.SimpleOnGestureListener} methods |
| 73 | {@link android.view.GestureDetector.OnGestureListener#onDown onDown()} and |
| 74 | {@link android.view.GestureDetector.OnGestureListener#onFling onFling()}. It also |
| 75 | overrides {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} |
| 76 | to return {@code false} since you don't need to animate a scroll.</p> |
| 77 | |
| 78 | |
| 79 | <p>It's common to use scrollers in conjunction with a fling gesture, but they |
| 80 | can be used in pretty much any context where you want the UI to display |
| 81 | scrolling in response to a touch event. For example, you could override {@link |
| 82 | android.view.View#onTouchEvent onTouchEvent()} to process touch events directly, |
| 83 | and produce a scrolling effect in response to those touch events.</p> |
| 84 | |
| 85 | <pre> |
| 86 | private OverScroller mScroller = new OverScroller(context); |
| 87 | |
| 88 | private GestureDetector.SimpleOnGestureListener mGestureListener |
| 89 | = new GestureDetector.SimpleOnGestureListener() { |
| 90 | @Override |
| 91 | public boolean onDown(MotionEvent e) { |
| 92 | // Abort any active scroll animations and invalidate. |
| 93 | mScroller.forceFinished(true); |
| 94 | // There is also a compatibility version: |
| 95 | // ViewCompat.postInvalidateOnAnimation |
| 96 | postInvalidateOnAnimation(); |
| 97 | return true; |
| 98 | } |
| 99 | |
| 100 | @Override |
| 101 | public boolean onScroll(MotionEvent e1, MotionEvent e2, |
| 102 | float distanceX, float distanceY) { |
| 103 | // You don't use a scroller in onScroll because you don't need to animate |
| 104 | // a scroll. The scroll occurs instantly in response to touch feedback. |
| 105 | return false; |
| 106 | } |
| 107 | |
| 108 | @Override |
| 109 | public boolean onFling(MotionEvent e1, MotionEvent e2, |
| 110 | float velocityX, float velocityY) { |
| 111 | // Before flinging, abort the current animation. |
| 112 | mScroller.forceFinished(true); |
| 113 | // Begin the scroll animation |
| 114 | mScroller.fling( |
| 115 | // Current scroll position |
| 116 | startX, |
| 117 | startY, |
| 118 | // Velocities, negated for natural touch response |
| 119 | (int) -velocityX, |
| 120 | (int) -velocityY, |
| 121 | // Minimum and maximum scroll positions. The minimum scroll |
| 122 | // position is generally zero and the maximum scroll position |
| 123 | // is generally the content size less the screen size. So if the |
| 124 | // content width is 1000 pixels and the screen width is 200 |
| 125 | // pixels, the maximum scroll offset should be 800 pixels. |
| 126 | minX, maxX, |
| 127 | minY, maxY, |
| 128 | // The maximum overscroll bounds. This is useful when using |
| 129 | // the EdgeEffect class to draw overscroll "glow" overlays. |
| 130 | mContentRect.width() / 2, |
| 131 | mContentRect.height() / 2); |
| 132 | // Invalidate to trigger computeScroll() |
| 133 | postInvalidateOnAnimation(); |
| 134 | return true; |
| 135 | } |
| 136 | }; |
| 137 | |
| 138 | @Override |
| 139 | public void computeScroll() { |
| 140 | super.computeScroll(); |
| 141 | |
| 142 | // Compute the current scroll offsets. If this returns true, then the |
| 143 | // scroll has not yet finished. |
| 144 | if (mScroller.computeScrollOffset()) { |
| 145 | int currX = mScroller.getCurrX(); |
| 146 | int currY = mScroller.getCurrY(); |
| 147 | |
| 148 | // Actually render the scrolled viewport, or actually scroll the |
| 149 | // view using View.scrollTo. |
| 150 | |
| 151 | // If currX or currY are outside the bounds, render the overscroll |
| 152 | // glow using EdgeEffect. |
| 153 | |
| 154 | } else { |
| 155 | // The scroll has finished. |
| 156 | } |
| 157 | }</pre> |
| 158 | |
| 159 | <p>For another example of scroller usage, see the <a href="http://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/view/ViewPager.java">source code</a> for the |
| 160 | {@link android.support.v4.view.ViewPager} class. It scrolls in response to flings, |
| 161 | and uses scrolling to implement the "snapping to page" animation.</p> |