Android里Scroller类是为了实现View平滑滚动的一个Helper类。通常在自定义的View时使用,在View中定义一个私有成员mScroller = new Scroller(context)。设置mScroller滚动的位置时,并不会导致View的滚动,通常是用mScroller记录/计算View滚动的位置,再重写View的computeScroll(),完成实际的滚动。

相关API介绍如下

Java代码
  <embed src="http://ipjmc.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf" type="application/x-shockwave-flash" width="14" height="15">
  </embed> 
  
  <a title="收藏这段代码">![收藏代码](http://ipjmc.iteye.com/images/icon_star.png)</a>
</div>
- mScroller.getCurrX() <span class="comment">//获取mScroller当前水平滚动的位置</span>

- mScroller.getCurrY() <span class="comment">//获取mScroller当前竖直滚动的位置</span>

- mScroller.getFinalX() <span class="comment">//获取mScroller最终停止的水平位置</span>

- mScroller.getFinalY() <span class="comment">//获取mScroller最终停止的竖直位置</span>

- mScroller.setFinalX(<span class="keyword">int</span> newX) <span class="comment">//设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置</span>

- mScroller.setFinalY(<span class="keyword">int</span> newY) <span class="comment">//设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置</span>

- 
- <span class="comment">//滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间</span>

- mScroller.startScroll(<span class="keyword">int</span> startX, <span class="keyword">int</span> startY, <span class="keyword">int</span> dx, <span class="keyword">int</span> dy) <span class="comment">//使用默认完成时间250ms</span>

- mScroller.startScroll(<span class="keyword">int</span> startX, <span class="keyword">int</span> startY, <span class="keyword">int</span> dx, <span class="keyword">int</span> dy, <span class="keyword">int</span> duration)

- 
- mScroller.computeScrollOffset() <span class="comment">//返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。</span>

举例说明,自定义一个CustomView,使用Scroller实现滚动:

Java代码
  <embed src="http://ipjmc.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf" type="application/x-shockwave-flash" width="14" height="15">
  </embed> 
  
  <a title="收藏这段代码">![收藏代码](http://ipjmc.iteye.com/images/icon_star.png)</a>
</div>
- <span class="keyword">import</span> android.content.Context;

- <span class="keyword">import</span> android.util.AttributeSet;

- <span class="keyword">import</span> android.util.Log;

- <span class="keyword">import</span> android.view.View;

- <span class="keyword">import</span> android.widget.LinearLayout;

- <span class="keyword">import</span> android.widget.Scroller;

- 
- <span class="keyword">public</span> <span class="keyword">class</span> CustomView <span class="keyword">extends</span> LinearLayout {

- 
- <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">&#8220;Scroller&#8221;</span>;

- 
- <span class="keyword">private</span> Scroller mScroller;

- 
- <span class="keyword">public</span> CustomView(Context context, AttributeSet attrs) {

- <span class="keyword">super</span>(context, attrs);

- mScroller = <span class="keyword">new</span> Scroller(context);

- }

- 
- <span class="comment">//调用此方法滚动到目标位置</span>

- <span class="keyword">public</span> <span class="keyword">void</span> smoothScrollTo(<span class="keyword">int</span> fx, <span class="keyword">int</span> fy) {

- <span class="keyword">int</span> dx = fx &#8211; mScroller.getFinalX();

- <span class="keyword">int</span> dy = fy &#8211; mScroller.getFinalY();

- smoothScrollBy(dx, dy);

- }

- 
- <span class="comment">//调用此方法设置滚动的相对偏移</span>

- <span class="keyword">public</span> <span class="keyword">void</span> smoothScrollBy(<span class="keyword">int</span> dx, <span class="keyword">int</span> dy) {

- 
- <span class="comment">//设置mScroller的滚动偏移量</span>

- mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);

- invalidate();<span class="comment">//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果</span>

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">void</span> computeScroll() {

- 
- <span class="comment">//先判断mScroller滚动是否完成</span>

- <span class="keyword">if</span> (mScroller.computeScrollOffset()) {

- 
- <span class="comment">//这里调用View的scrollTo()完成实际的滚动</span>

- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());

- 
- <span class="comment">//必须调用该方法,否则不一定能看到滚动效果</span>

- postInvalidate();

- }

- <span class="keyword">super</span>.computeScroll();

- }

- }

- 转自:http://ipjmc.iteye.com/blog/1615828





&nbsp;





public class CustomView extends LinearLayout {





private static final String TAG = CustomView.class.getName();

// 定义一个滑动 private Scroller mScroller; //手势 private GestureDetector mGestureDetector;

public CustomView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle); mScroller = new Scroller(context); mGestureDetector = new GestureDetector(context, new CustomGestureListener()); }

public CustomView(Context context, AttributeSet attrs) {

super(context, attrs); mScroller = new Scroller(context); mGestureDetector = new GestureDetector(context, new CustomGestureListener()); }

public CustomView(Context context) {

super(context); mScroller = new Scroller(context); mGestureDetector = new GestureDetector(context, new CustomGestureListener()); // setClickable(true); // setLongClickable(true); }

// 调用此方法滚动到目标位置

public void smoothScrollTo(int fx, int fy) { int dx = fx – mScroller.getFinalX(); int dy = fy – mScroller.getFinalY(); smoothScrollBy(dx, dy); }

// 调用此方法设置滚动的相对偏移

public void smoothScrollBy(int dx, int dy) { // 设置mScroller的滚动偏移量 mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy); invalidate();// 这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果 }

/**
  • 完成实际的滚动 */ @Override public void computeScroll() { // 判断Scroll是否滚动完成 if (mScroller.computeScrollOffset()) { // 调用View 的scrollto完成实际的滚动 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //必须调用该方法,否则不一定能看到滚动效果 postInvalidate(); } super.computeScroll(); }

    @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP : Log.e(TAG, “get Sy” + getScrollY()); smoothScrollTo(0, 0); break; default: return mGestureDetector.onTouchEvent(event); } return super.onTouchEvent(event); }

    class CustomGestureListener implements GestureDetector.OnGestureListener {

    @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return true; }

    @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub

    }

    @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return false; }

    @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

    int dis = (int)((distanceY-0.5)/2); Log.e(TAG, dis + “.”); smoothScrollBy(0, dis); return false; }

    @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub

    }

    @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub return false; }

    } }

     

    android 使用Scroller实现缓慢移动

    转载请声明:http://bbs.niuzhi.cc/thread-24-1-1.html

    在Launcher中的Workspace中实现了左右屏幕切换效果,里面就用到了Scroller记录滑动轨迹,实现一种缓慢地向左或向右移动的效果,这里我对这种效果进行总结:

    我们先看一个例子:点击按钮时红经块会从左边缓慢地移向左右,这个该怎么实现呢

    红色块在右边 

    我们先来看一下,Scroller,这个对象里有startScroll方法

    void android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration) 第一个参数是起始移动的x坐标值,第二个是起始移动的y坐标值,第三个第四个参数都是移到某点的坐标值,而**duration **当然就是执行移动的时间。这个有什么用呢。要知道有什么用还得再看一个方法

boolean android.widget.[Scroller](http://blog.csdn.net/c_weibin/article/details/7438323).computeScrollOffset()
当startScroll执行过程中即在duration时间内,**computeScrollOffset  **方法会一直返回false,但当动画执行完成后会返回返加true.





有了这两个方法还不够,我们还需要再重写viewGroup的一个方法,





**computeScroll 这个方法什么时候会被调用呢**





**官网上这样说的**

public void computeScroll ()

Since: [API Level 1](http://developer.android.com/guide/appendix/api-levels.html#level1)
    Called by a parent to request that a child update its values for mScrollX and mScrollY if necessary. This will typically be done if the child is animating a scroll using a `&lt;a href="http://developer.android.com/reference/android/widget/Scroller.html">Scroller&lt;/a>` object.
  

</div>
当我们执行ontouch或invalidate()或postInvalidate()都会导致这个方法的执行





**所以我们像下面这样调用,**postInvalidate执行后,会去调**computeScroll 方法,而这个方法里再去调<strong>postInvalidate,这样******就可以不断地去调用scrollTo方法了,直到mScroller动画结束,当然第一次时,我们需要手动去调用一次**postInvalidate才会去调用 **</strong>

computeScroll 方法

**[java]** [view plain](http://blog.csdn.net/c_weibin/article/details/7438323#)[copy](http://blog.csdn.net/c_weibin/article/details/7438323#)
    <div>
      <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_1">
      </embed>
    </div>
  </div>
</div>


  - <span class="annotation">@Override</span>
  
  - <span class="keyword">public</span> <span class="keyword">void</span> computeScroll() {
  
  - <span class="keyword">if</span> (mScroller.computeScrollOffset()) {
  
  - scrollTo(mScroller.getCurrX(), <span class="number"></span>);
  
  - postInvalidate();
  
  - }
  
  - }
下面附上上面那个例子的源代码





首先是MyViewGroup.java
**[java]** [view plain](http://blog.csdn.net/c_weibin/article/details/7438323#)[copy](http://blog.csdn.net/c_weibin/article/details/7438323#)
    <div>
      <embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_2">
      </embed>
    </div>
  </div>
</div>


  - <span class="keyword">package</span> com.wb;
  
  - 
  - <span class="keyword">import</span> android.content.Context;
  
  - <span class="keyword">import</span> android.util.AttributeSet;
  
  - <span class="keyword">import</span> android.view.View;
  
  - <span class="keyword">import</span> android.view.ViewGroup;
  
  - <span class="keyword">import</span> android.widget.LinearLayout;
  
  - <span class="keyword">import</span> android.widget.Scroller;
  
  - 
  - <span class="keyword">public</span> <span class="keyword">class</span> MyViewGroup <span class="keyword">extends</span> LinearLayout {
  
  - <span class="keyword">private</span> <span class="keyword">boolean</span> s1=<span class="keyword">true</span>;
  
  - Scroller mScroller=<span class="keyword">null</span>;
  
  - <span class="keyword">public</span> MyViewGroup(Context context, AttributeSet attrs) {
  
  - <span class="keyword">super</span>(context, attrs);
  
  - mScroller=<span class="keyword">new</span> Scroller(context);
  
  - <span class="comment">// TODO Auto-generated constructor stub</span>
  
  - }
  
  - <span class="annotation">@Override</span>
  
  - <span class="keyword">public</span> <span class="keyword">void</span> computeScroll() {
  
  - <span class="keyword">if</span> (mScroller.computeScrollOffset()) {
  
  - scrollTo(mScroller.getCurrX(), <span class="number"></span>);
  
  - postInvalidate();
  
  - }
  
  - }
  
  - <span class="keyword">public</span> <span class="keyword">void</span> beginScroll(){
  
  - <span class="keyword">if</span> (!s1) {
  
  - mScroller.startScroll(<span class="number"></span>, <span class="number"></span>, <span class="number"></span>, <span class="number"></span>, <span class="number">1000</span>);
  
  - s1 = <span class="keyword">true</span>;
  
  - } <span class="keyword">else</span> {
  
  - mScroller.startScroll(<span class="number"></span>, <span class="number"></span>, &#8211;<span class="number">500</span>, <span class="number"></span>, <span class="number">1000</span>);
  
  - s1 = <span class="keyword">false</span>;
  
  - }
  
  - invalidate();
  
  - }
  
  - }
然后是WheelActivity.java
**[java]** [view plain](http://blog.csdn.net/c_weibin/article/details/7438323#)[copy](http://blog.csdn.net/c_weibin/article/details/7438323#)
    <div>
      <embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_3">
      </embed>
    </div>
  </div>
</div>


  - <span class="keyword">package</span> com.wb;
  
  - 
  - <span class="keyword">import</span> android.app.Activity;
  
  - <span class="keyword">import</span> android.graphics.Color;
  
  - <span class="keyword">import</span> android.os.Bundle;
  
  - <span class="keyword">import</span> android.view.Gravity;
  
  - <span class="keyword">import</span> android.view.View;
  
  - <span class="keyword">import</span> android.view.ViewGroup;
  
  - <span class="keyword">import</span> android.widget.AbsListView;
  
  - <span class="keyword">import</span> android.widget.AbsListView.LayoutParams;
  
  - <span class="keyword">import</span> android.widget.AbsListView.OnScrollListener;
  
  - <span class="keyword">import</span> android.widget.Adapter;
  
  - <span class="keyword">import</span> android.widget.BaseAdapter;
  
  - <span class="keyword">import</span> android.widget.ListView;
  
  - <span class="keyword">import</span> android.widget.TextView;
  
  - 
  - <span class="keyword">public</span> <span class="keyword">class</span> WheelActivity <span class="keyword">extends</span> Activity {
  
  - 
  - <span class="keyword">private</span> ListView listView = <span class="keyword">null</span>;
  
  - <span class="keyword">private</span> MyViewGroup myViewGroup;
  
  - 
  - <span class="annotation">@Override</span>
  
  - <span class="keyword">public</span> <span class="keyword">void</span> onCreate(Bundle savedInstanceState) {
  
  - <span class="keyword">super</span>.onCreate(savedInstanceState);
  
  - setContentView(R.layout.main);
  
  - myViewGroup = (MyViewGroup) findViewById(R.id.myviewGroup);
  
  - 
  - }
  
  - 
  - <span class="keyword">public</span> <span class="keyword">void</span> scroll(View view) {
  
  - 
  - myViewGroup.beginScroll();
  
  - 
  - }
  
  - 
  - }
main.xml
**[html]** [view plain](http://blog.csdn.net/c_weibin/article/details/7438323#)[copy](http://blog.csdn.net/c_weibin/article/details/7438323#)
    <div>
      <embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_4">
      </embed>
    </div>
  </div>
</div>


  - <span class="tag"><?</span><span class="tag-name">xml</span> <span class="attribute">version</span>=<span class="attribute-value">&#8220;1.0&#8221;</span> <span class="attribute">encoding</span>=<span class="attribute-value">&#8220;utf-8&#8221;</span><span class="tag">?></span>
  
  - <span class="tag"><</span><span class="tag-name">LinearLayout</span> <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span>
  
  - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span>
  
  - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span>
  
  - <span class="attribute">android:orientation</span>=<span class="attribute-value">&#8220;vertical&#8221;</span> <span class="tag">></span>
  
  - 
  - <span class="tag"><</span><span class="tag-name">Button</span>
  
  - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span>
  
  - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>
  
  - <span class="attribute">android:text</span>=<span class="attribute-value">&#8220;scroll&#8221;</span>
  
  - <span class="attribute">android:onClick</span>=<span class="attribute-value">&#8220;scroll&#8221;</span> <span class="tag">/></span>
  
  - 
  - <span class="tag"><</span><span class="tag-name">com.wb.MyViewGroup</span>
  
  - <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span>
  
  - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span>
  
  - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span>
  
  - <span class="attribute">android:orientation</span>=<span class="attribute-value">&#8220;vertical&#8221;</span> <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/myviewGroup&#8221;</span><span class="tag">></span>
  
  - 
  - <span class="tag"><</span><span class="tag-name">TextView</span>
  
  - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>
  
  - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span>
  
  - <span class="attribute">android:background</span>=<span class="attribute-value">&#8220;#ff0000&#8221;</span>
  
  - <span class="attribute">android:text</span>=<span class="attribute-value">&#8220;我在這&#8221;</span><span class="tag">/></span>
  
  - 
  - 
  - <span class="tag"></</span><span class="tag-name">com.wb.MyViewGroup</span><span class="tag">></span>
  
  - 
  - <span class="tag"></</span><span class="tag-name">LinearLayout</span><span class="tag">></span>
源代码下载地址:[http://download.csdn.net/detail/c_weibin/4208751](http://download.csdn.net/detail/c_weibin/4208751)

 

💬 评论