`
iaiai
  • 浏览: 2180901 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android Scroller的使用及自我理解

 
阅读更多
以前做一个看书的项目时,有个翻书的功能,当手指滑动书页移动一段然后抬起后,需要页面view自动完成剩余的操作:
1、当滑动距离大于某个设定值时,自动滚动到末尾处,翻一页。
2、当滑动距离小于该设定值时,自动回滚到起始处,还原。
  实现这个功能,当时是用了Scroller来实现的。

我一步步来说下吧:

1、Scroller的最简单用法解释

  网上有很多关于Scroller的用法,很多讲的真的很不错,但我觉得,他们的讲解还是过于繁琐,这里我就最最简单的说下吧,这个Scroller到底怎么回事,且看下面代码:

   下面的这个demo1,就一个布局,linearlayout上放置一个button,点击button,我们就调用Scroller的相关方法:

布局文件xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
   >
     <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_margin="10dp"
        android:text="run  Scroller " />
</LinearLayout>

控制器activity:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.Scroller;
 
public class MainActivity extends Activity {
    private Scroller mScroller;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mScroller = new Scroller(this);
        this.setContentView(R.layout.activity_main);    
        findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mScroller.startScroll(-10, -100,- 200, -300, 1000);
                new Thread(){
                    public void run() {
                        while(mScroller.computeScrollOffset())// 如果mScroller没有调用startScroll,这里将会返回false。
                        {
                            Log.i("scroller", "getCurrX()= "+mScroller.getCurrX()+"     getCurrY()="+mScroller.getCurrY());
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
 
                        }
 
                    };
 
                }.start();
            }
        });
    }
}

运行后,点击按钮,就可以看到效果,且看控制台日志输出:
引用
05-02 11:30:55.455: I/scroller(30287): getCurrX()= -10     getCurrY()=-100
05-02 11:30:55.510: I/scroller(30287): getCurrX()= -26     getCurrY()=-124
05-02 11:30:55.557: I/scroller(30287): getCurrX()= -63     getCurrY()=-180
05-02 11:30:55.612: I/scroller(30287): getCurrX()= -111     getCurrY()=-251
05-02 11:30:55.658: I/scroller(30287): getCurrX()= -144     getCurrY()=-301
05-02 11:30:55.713: I/scroller(30287): getCurrX()= -166     getCurrY()=-334
05-02 11:30:55.760: I/scroller(30287): getCurrX()= -181     getCurrY()=-356
05-02 11:30:55.815: I/scroller(30287): getCurrX()= -191     getCurrY()=-371
05-02 11:30:55.862: I/scroller(30287): getCurrX()= -197     getCurrY()=-381
05-02 11:30:55.916: I/scroller(30287): getCurrX()= -201     getCurrY()=-387
05-02 11:30:55.963: I/scroller(30287): getCurrX()= -204     getCurrY()=-391
05-02 11:30:56.018: I/scroller(30287): getCurrX()= -206     getCurrY()=-394
05-02 11:30:56.065: I/scroller(30287): getCurrX()= -208     getCurrY()=-396
05-02 11:30:56.119: I/scroller(30287): getCurrX()= -208     getCurrY()=-398
05-02 11:30:56.166: I/scroller(30287): getCurrX()= -209     getCurrY()=-398
05-02 11:30:56.221: I/scroller(30287): getCurrX()= -209     getCurrY()=-399
05-02 11:30:56.268: I/scroller(30287): getCurrX()= -210     getCurrY()=-399
05-02 11:30:56.322: I/scroller(30287): getCurrX()= -210     getCurrY()=-400
05-02 11:30:56.369: I/scroller(30287): getCurrX()= -210     getCurrY()=-400
05-02 11:30:56.424: I/scroller(30287): getCurrX()= -210     getCurrY()=-400
05-02 11:30:56.471: I/scroller(30287): getCurrX()= -210     getCurrY()=-400

从日志输出的数据一看,你应该能大致知道这个scroller的作用了吧
mScroller.startScroll(-10, -100,- 200, -300, 1000);

我们在button的事件处理里做的是调用了
public void startScroll (int startX, int startY, int dx, int dy,int duration)

这个方法,然后我们在线程中一直查看scroller的几个属性数值,然后打印了出来,从日志可以看出,scroller中的这些数值,是按(int startX, int startY, int dx, int dy)来变化的,并且是在intduration这个时间段内完成的。我们设置线程的睡眠时间是50毫秒,而打印了总共20条日志,20* 50 = 1000,正好是我们设置的这个时间。

如果我们在调用了
public void startScroll (int startX, int startY, int dx, int dy,in tduration) 

让我们的view重新绘制,并且利用scroller的几个属性数值来确定view的位置或其他的什么,然后不断的循环调用,你说会出现什么呢?答案就不用说了吧(view会动起来吧),这个就是我们平时在项目中利用scroller的主要思路了,而一般的时候,我们会多绕了几道弯儿而已。

2、Scroller结合view的用法

  首先,我们简单的介绍下view,查看android的源码,你会发现如下的方法:
/**
* 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 {@link android.widget.Scroller Scroller}
* object.
*/
public void computeScroll(){}

该方法就是留给我们去覆写的,它一般都会被该view的父类viewGroup在绘制该view时调用,具体的,就不多说了,大家可以参见相关博客,如果我们在这个方法里,调用 scroller的相关属性来修改view的相关属性或调用其他方法,是不是可以做很多事呢?
  下面看看改造后的demo2:

先介绍一个函数,view下面的:
public void scrollTo (int x, int y) Added in API level 1
Set the scrolled position of your view. This will cause a call to onScrollChanged(int, int, int, int) and the view will be invalidated.

Parameters
x   the x position to scroll to
y   the y position to scroll to

该函数可以使view中的内容滚动到指定位置:
demo2:

该demo没有xml,直接就一个activity:
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Scroller;
 
public class MainActivity extends Activity {
    LinearLayout demoSubview1, demoSubview2, demoViewGroup;
    private Scroller mScrollerViewGroup;
    private Scroller mScrollerView;
//  private Scroller mScroller;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mScrollerViewGroup = new Scroller(this);
        mScrollerView = new Scroller(this);
        demoSubview1 = new DemoView(this);
        demoSubview2 = new DemoView(this);
 
        demoSubview1.setBackgroundColor(this.getResources().getColor(
                android.R.color.darker_gray));
        demoSubview2.setBackgroundColor(this.getResources().getColor(
                android.R.color.white));
        demoViewGroup = new DemoViewGroup(this);
        demoViewGroup.setOrientation(LinearLayout.VERTICAL);
        LinearLayout.LayoutParams p0 = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.FILL_PARENT,
                LinearLayout.LayoutParams.FILL_PARENT);
        this.setContentView(demoViewGroup, p0);
 
        LinearLayout.LayoutParams p1 = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.FILL_PARENT,
                LinearLayout.LayoutParams.FILL_PARENT);
        p1.weight = 1;
        demoViewGroup.addView(demoSubview1, p1);
        LinearLayout.LayoutParams p2 = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.FILL_PARENT,
                LinearLayout.LayoutParams.FILL_PARENT);
        p2.weight = 1;
        demoViewGroup.addView(demoSubview2, p2);
        DemoButton btn1 = new DemoButton(this);
        btn1.setText("run  Scroller in viewGroup");
        btn1.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                 
                mScrollerViewGroup.startScroll(-10, -100,- 200, -300, 1000);
                new Thread(){
                    public void run() {
                        while(mScrollerViewGroup.computeScrollOffset())// 如果mScroller没有调用startScroll,这里将会返回false。
                        {
                            Log.i("scroller", "getCurrX()= "+mScrollerViewGroup.getCurrX()+"     getCurrY()="+mScrollerViewGroup.getCurrY());
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
 
                        }
 
                    };
 
                }.start();
            }
        });
 
        demoSubview1.addView(btn1);
        DemoButton btn2 = new DemoButton(this);
        btn2.setText("run  Scroller in view");
        btn2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                 
                mScrollerView.startScroll(-10, -100,- 200, -300, 1000);
                new Thread(){
                    public void run() {
                        while(mScrollerView.computeScrollOffset())// 如果mScroller没有调用startScroll,这里将会返回false。
                        {
                            Log.i("scroller", "getCurrX()= "+mScrollerView.getCurrX()+"     getCurrY()="+mScrollerView.getCurrY());
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                             
                        }
                         
                    };
                     
                }.start();
            }
        });
         
        demoSubview2.addView(btn2);
         
    }
 
    class DemoButton extends Button {
        public DemoButton(Context ctx) {
            super(ctx);
        }
 
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Log.i("DemoButton",  "------ onDraw------");
        }
         
        public void computeScroll() {
            Log.i("DemoButton", " --------------------computeScroll-----------");
        //  Log.i(TAG, "getCurrX = " + mScroller.getCurrX());
            if (mScrollerView.computeScrollOffset())// 如果mScroller没有调用startScroll,这里将会返回false。
            {
                // 因为调用computeScroll函数的是MyLinearLayout实例,
                // 所以调用scrollTo移动的将是该实例的孩子,也就是MyButton实例
                scrollTo(mScrollerView.getCurrX(), 0);
                Log.i("DemoButton", "getCurrX = " + mScrollerView.getCurrX());
 
                // 继续让系统重绘
                invalidate();
            }
        }
    }
 
    class DemoView extends LinearLayout {
        public DemoView(Context ctx) {
            super(ctx);
        }
 
        @Override
        public void computeScroll() {
            Log.i("DemoView", " DemoView --------------------computeScroll-----------");
            if (mScrollerViewGroup.computeScrollOffset())// 如果mScroller没有调用startScroll,这里将会返回false。
            {
                // 因为调用computeScroll函数的是MyLinearLayout实例,
                // 所以调用scrollTo移动的将是该实例的孩子,也就是MyButton实例
                scrollTo(mScrollerViewGroup.getCurrX(), 0);
                Log.i("DemoView", "getCurrX = " + mScrollerViewGroup.getCurrX());
                // 继续让系统重绘
                getChildAt(0).invalidate();
            }
        }
    }
 
    class DemoViewGroup extends LinearLayout {
        public DemoViewGroup(Context ctx) {
            super(ctx);
        }
 
        @Override
        protected void dispatchDraw(Canvas canvas) {
            Log.i("DemoViewGroup", "contentview dispatchDraw");
            super.dispatchDraw(canvas);
        }
    }
}

运行程序效果:

点击第一个button后,日志如下:
引用
05-02 13:38:02.291: I/DemoViewGroup(332): contentview dispatchDraw
05-02 13:38:02.291: I/DemoView(332):  DemoView --------------------computeScroll------
05-02 13:38:02.301: I/DemoButton(332):  --------------------computeScroll-----------
05-02 13:38:02.311: I/DemoButton(332): ------ onDraw------
05-02 13:38:02.311: I/DemoView(332):  DemoView --------------------computeScroll------
05-02 13:38:02.311: I/DemoButton(332):  --------------------computeScroll-----------
05-02 13:38:02.311: I/DemoButton(332): ------ onDraw------
05-02 13:39:50.432: I/scroller(332): getCurrX()= -11     getCurrY()=-101</b> 05-02 13:39:50.432: I/DemoViewGroup(332): contentview dispatchDraw
05-02 13:39:50.432: I/DemoView(332):  DemoView --------------------computeScroll------
05-02 13:39:50.432: I/DemoView(332): getCurrX = -12
05-02 13:39:50.442: I/DemoButton(332):  --------------------computeScroll-----------
05-02 13:39:50.442: I/DemoButton(332): ------ onDraw------
......................<b>此处省略部分日志</b>...................................................
05-02 13:39:51.412: I/DemoViewGroup(332): contentview dispatchDraw
05-02 13:39:51.412: I/DemoView(332):  DemoView --------------------computeScroll------
05-02 13:39:51.412: I/DemoView(332): getCurrX = -210
05-02 13:39:51.412: I/DemoButton(332):  --------------------computeScroll-----------
05-02 13:39:51.422: I/DemoButton(332): ------ onDraw------
05-02 13:39:51.432: I/DemoViewGroup(332): contentview dispatchDraw
05-02 13:39:51.432: I/DemoView(332):  DemoView --------------------computeScroll------
05-02 13:39:51.432: I/DemoButton(332):  --------------------computeScroll-----------
05-02 13:39:51.432: I/DemoButton(332): ------ onDraw------

通过日志,看出什么了没?
另外,通过该日志,你了解了view的绘画机制没,应该能发现吧。

最终的效果图片:

点击buttom2,日志就不给出了,效果图片如下:

button内的文字移动到了不可见处,

所以调用scrollTo移动的将是该view的内容,如果是viewGroup的话,就移动了它的孩子view了

所以调用scrollTo移动的将是该实例的孩子,也就是MyButton实例

这会儿明白了没?
后面我会尝试的自己模拟一个scrolelr,其实他的作用就是存储一些基本的数值,其他的啥也没做,也和view没有真正关系的,它只是被动的被调用的
  • 大小: 60.2 KB
  • 大小: 50 KB
  • 大小: 55.3 KB
分享到:
评论

相关推荐

    android Scroller使用小例子

    在Android开发中,`Scroller`是一个非常重要的工具类,主要用于实现平滑的滚动效果。它并不直接控制View的移动,而是提供一个离散的、可...理解并熟练掌握`Scroller`的使用,对于提升Android应用的用户体验至关重要。

    android scroller学习demo

    本示例“android scroller学习demo”将带你深入理解如何利用`Scroller`实现类似QQ ListView的侧滑删除效果。下面我们将详细探讨`Scroller`的工作原理以及如何在实际项目中应用它。 `Scroller`并非一个视图控件,...

    Android Scroller完全解析

    总结,`Scroller`是Android中实现平滑滚动效果的重要工具,通过合理的使用和定制,我们可以创造出丰富多样的滚动动画。理解其工作原理并结合`Interpolator`,可以提升用户界面的交互体验。在实际项目中,应根据需求...

    Android 使用Scroller自动滚动第二种实现

    通过分析该项目的代码,可以更深入地理解Scroller的工作原理和使用方法。 总之,Scroller是Android中实现平滑滚动动画的一个高效工具,它允许开发者自定义滚动速度和时间,从而创建出各种定制化的滚动效果。通过...

    Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果 源码程序

    Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果,项目详情http://blog.csdn.net/xiaanming/article/details/17539199

    Android之Scroller(滑动)完全解析

    在Android开发中,`Scroller`是一个非常重要的组件,它主要用于处理平滑的滚动效果,尤其是在没有用户交互的情况下。在本篇文章中,我们将深入探讨`Scroller`的工作原理,以及如何在实际应用中使用它来实现平滑滚动...

    Android Scroller大揭秘

    Android Scroller是Android系统中用于实现平滑滚动效果的重要组件,它主要用于控制View或者 ViewGroup的动画滚动效果,比如ScrollView、...理解和熟练运用Scroller,对于提升Android应用的用户体验至关重要。

    Android Scroller练习-仿ViewPager效果

    通过这个练习,你可以深入理解`Scroller`的工作原理,以及如何与自定义View配合实现复杂的滑动效果。同时,这也是提升Android开发技能的一个好方法,因为你将直接与Android的绘制机制打交道,对View的生命周期和触摸...

    Android Scroller实现View弹性滑动Demo

    首先,理解`Scroller`的工作原理是关键。`Scroller`并不直接改变View的位置,而是通过计算出一系列连续的坐标点,这些坐标点代表了滚动过程中的位置变化。开发者需要在`onDraw()`或`computeScroll()`方法中获取当前...

    android Scroller粗暴分析

    总的来说,`Scroller`是Android中实现平滑滚动效果的重要工具,理解其工作原理和使用方法对于提升用户体验至关重要。通过合理地利用`Scroller`,我们可以为用户创造出更加流畅、自然的交互体验。

    android scroller滑动效果简单demo

    在Android开发中,`Scroller`...理解并熟练掌握`Scroller`的使用,能帮助开发者创造出更加流畅和自然的用户界面。在`MyScroller`这个Demo中,你可以看到如何将理论知识转化为实际应用,进一步加深对`Scroller`的理解。

    深入理解Android中Scroller的滚动原理

    Scroller在Android中是一个核心组件,它主要用于实现View的平滑滚动效果,使得视图能够按照预设的时间和轨迹进行连续、平滑的移动,而不是简单地瞬移。Scroller本身并不直接改变View的位置,而是提供计算滚动过程的...

    Android Scroller及下拉刷新组件原理解析

    Android事件拦截机制 Android中事件的传递和拦截和View树结构是相关联的,在View树中,分为叶子节点和普通节点,普通节点有子节点只能是ViewGroup,叶子节点可以是View或者ViewGroup。Android和事件分发拦截相关的...

    Android利用Scroller实现简单的物体漂浮移动效果

    在Android开发中,动画效果是提升用户体验的...理解`Scroller`的工作原理和使用方式对于开发流畅的滚动界面和动画至关重要。在实际项目中,`Scroller`通常与`View`的滚动方法结合使用,创造出更加丰富的用户交互体验。

    Android使用Scroller实现弹性滑动效果

    本文实例为大家分享了Android使用Scroller实现弹性滑动展示的具体代码,供大家参考,具体内容如下 scrollTo、scrollBy View内部为了实现滑动提供了这两个方法,但是使用这两个方法滑动的效果是瞬间的不够平滑,如何...

    Android仿ViewPager,自定义Scroller模拟动画

    首先,我们要理解Scroller在Android中的作用。Scroller并非一个View或者ViewGroup,而是一个辅助类,用于处理平滑滚动的动画效果。它不直接绘制视图,而是提供计算下一帧位置的方法,供ViewGroup在滑动过程中调用。...

    Scroller使用demo

    结合提供的文件列表,这个"Scroller使用demo"项目可能包含了一个简单的Android应用,演示了如何在自定义View中使用`Scroller` 来实现平滑的滑动效果。通过阅读`build.gradle` 文件可以了解项目的构建依赖,`README....

    详解Android Scroller与computeScroll的调用机制关系

    在Android开发中,`Scroller`和`computeScroll`是两个关键的概念,它们与ViewGroup的滚动动画密切相关。本文将详细解析这两个概念及其调用机制之间的关系。 首先,`Scroller`是一个内部类,它并不直接参与ViewGroup...

Global site tag (gtag.js) - Google Analytics