Scroll类之所以不好理解是因为没有搞清楚View的绘制流程。

1)简单来讲 viewgroup重绘时依次会调用  dispatchDraw -- drawChild --child.computeScroll()。

computeScroll是一个空函数,可以在里面写代码。

2)Scroller类一些api:

mScroller.getCurrX() //获取mScroller当前水平滚动的位置
mScroller.getCurrY() //获取mScroller当前竖直滚动的位置
mScroller.getFinalX() //获取mScroller最终停止的水平位置
mScroller.getFinalY() //获取mScroller最终停止的竖直位置
mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置
mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置 //滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间
mScroller.startScroll(int startX, int startY, int dx, int dy) //使用默认完成时间250ms
mScroller.startScroll(int startX, int startY, int dx, int dy, int duration) mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。

其中非常重要的startScroll()和computeScrollOffset()函数。

startScroll函数的功能是设置一些值,最重要的值是设置了一个滚动开始时间和持续时间,其源码如下:

    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}

computeScrollOffset()是用来计算当前时间点理论上能够滚到的x,y坐标。

如果滚动持续时间到了则返回false,否则返回true并计算坐标。mCurrX和mCurrY得到更新。源码如下:

    public boolean computeScrollOffset() {
if (mFinished) {
return false;
} int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
float x = timePassed * mDurationReciprocal; if (mInterpolator == null)
x = viscousFluid(x);
else
x = mInterpolator.getInterpolation(x); mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
case FLING_MODE:
final float t = (float) timePassed / mDuration;
final int index = (int) (NB_SAMPLES * t);
float distanceCoef = 1.f;
float velocityCoef = 0.f;
if (index < NB_SAMPLES) {
final float t_inf = (float) index / NB_SAMPLES;
final float t_sup = (float) (index + 1) / NB_SAMPLES;
final float d_inf = SPLINE_POSITION[index];
final float d_sup = SPLINE_POSITION[index + 1];
velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
distanceCoef = d_inf + (t - t_inf) * velocityCoef;
} mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f; mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
// Pin to mMinX <= mCurrX <= mMaxX
mCurrX = Math.min(mCurrX, mMaxX);
mCurrX = Math.max(mCurrX, mMinX); mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
// Pin to mMinY <= mCurrY <= mMaxY
mCurrY = Math.min(mCurrY, mMaxY);
mCurrY = Math.max(mCurrY, mMinY); if (mCurrX == mFinalX && mCurrY == mFinalY) {
mFinished = true;
} break;
}
}
else {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
return true;
}

3)通过1、2我们可以知道如果要实现平滑滚动则需要在computeScroll函数里调用computeScrollOffset()来更新Scroller里面的mCurrX 和mCurrY,然后利用

scrollTo(mCurrX, mCurrY) 来让View的x、y坐标滚动到指定位置。此时并不一定会导致view重绘,手动调用postInvalidate()自上而下重绘view树。

注意scrollTo只会导致该view的内容发生偏移,并不会导致该view的位置偏移。比如对Button进行scrollTo 会导致Button里面的text发生偏移,而Button的位置不会发生偏移。

4) 有了上面的分析后下面是一段小实例,单击按钮后,按钮会慢慢下移。

CustomView.java:

public class CustomView extends LinearLayout {

    private Scroller mScroller = null;
private Context mContext; public CustomView(Context context) {
super(context);
mContext = context;
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
} private void init() {
if (mScroller == null) {
mScroller = new Scroller(mContext);
}
this.setOrientation(VERTICAL);
Button btn = new Button(mContext);
btn.setText("按钮");
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
this.addView(btn, params);
this.setBackgroundColor(Color.YELLOW);
} //调用此方法设置滚动到目标位置
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.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, 10000);
invalidate();
} @Override
public void computeScroll() {
// TODO Auto-generated method stub //查看是否滚动结束了,true表示没有结束
if (mScroller.computeScrollOffset()) {
//调用view的滚动函数,进行实际滚动。
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//只有postInvalidate了才能循环刷新。
postInvalidate();
}
super.computeScroll();
}
}

MainActivity.java:

public class MainActivity extends Activity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
final CustomView view = new CustomView(this);
setContentView(view);
     //给button添加onClick监听
view.getChildAt(0).setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
view.smoothScrollBy(0, -100);
}
});
} }

参考网页:http://www.cnblogs.com/PDW-Android/p/3653253.html

http://blog.csdn.net/gemmem/article/details/7321910

http://www.open-open.com/lib/view/open1328834050046.html

Scroller类的使用总结的更多相关文章

  1. 简单的ViewPager了解Scroller类

    View滑动是自定义ViewGroup中十分常见的一个功能.Android提供了多种View滑动的方法. layout方法 offsetLeftAndRight()与offsetTopAndBotto ...

  2. 在Android中动画移动一个View的位置,采用Scroller类实现Android动画之 View移动

    在Android中动画移动一个View的位置,采用Scroller类实现 今天说最近自己遇到的一个问题,就是要用动画效果来移动一个VIew的位置. 这个具体的情况是,需要做一个SlidingMenu的 ...

  3. Android中滑屏实现----手把手教你如何实现触摸滑屏以及Scroller类详解

    前言:  虽然本文标题的有点标题党的感觉,但无论如何,通过这篇文章的学习以及你自己的实践认知,写个简单的滑屏小 Demo还是just so so的. 友情提示: 在继续往下面读之前,希望您对以下知识点 ...

  4. Android Scroller类的详细分析

    尊重原创作者,转载请注明出处: http://blog.csdn.net/gemmem/article/details/7321910 Scroller这个类理解起来有一定的困难,刚开始接触Scrol ...

  5. Android 界面滑动实现---Scroller类 从源码和开发文档中学习(让你的布局动起来)

    在android学习中,动作交互是软件中重要的一部分,其中的Scroller就是提供了拖动效果的类,在网上,比如说一些Launcher实现滑屏都可以通过这个类去实现..   例子相关博文:Androi ...

  6. Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源码

    在android学习中,动作交互是软件中重要的一部分,其中的Scroller就是提供了拖动效果的类,在网上,比如说一些Launcher实现滑屏都可以通过这个类去实现.下面要说的就是上次Scroller ...

  7. Android自己定义组件系列【2】——Scroller类

    在上一篇中介绍了View类的scrollTo和scrollBy两个方法,对这两个方法不太了解的朋友能够先看<自己定义View及ViewGroup> scrollTo和scrollBy尽管实 ...

  8. Android VelocityTracker类和Scroller类

    VelocityTracker类:用于跟踪触屏事件的速度,通常使用VelocityTracker的步骤如下: static VelocityTracker obtain():获取一个VelocityT ...

  9. Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源代码

    在android学习中,动作交互是软件中重要的一部分.当中的Scroller就是提供了拖动效果的类,在网上.比方说一些Launcher实现滑屏都能够通过这个类去实现.以下要说的就是上次Scroller ...

随机推荐

  1. Django会话,用户和注册之用户认证

    通过session,我们可以在多次浏览器请求中保持数据, 接下来的部分就是用session来处理用户登录了. 当然,不能仅凭用户的一面之词,我们就相信,所以我们需要认证. 当然了,Django 也提供 ...

  2. requests模块demo

    import urllib.request import requests from requests.auth import HTTPBasicAuth from requests.auth imp ...

  3. 深入解读Job System(1)

    https://mp.weixin.qq.com/s/IY_zmySNrit5H8i0CcTR7Q 通常而言,最好不要把Unity实体组件系统ECS和Job System看作互相独立的部分,要把它们看 ...

  4. loj #2254. 「SNOI2017」一个简单的询问

    #2254. 「SNOI2017」一个简单的询问 题目描述 给你一个长度为 NNN 的序列 aia_ia​i​​,1≤i≤N1\leq i\leq N1≤i≤N,和 qqq 组询问,每组询问读入 l1 ...

  5. Linux根目录结构

    1:  bin目录 此目录存放所有二进制命令(用户) 2:  boot目录 Linux内核及引导系统程序所需的目录 3:  dev目录 所有设备文件的目录(如声卡.磁盘.光驱) 4:  etc目录 二 ...

  6. Python中使用Beautiful Soup库的超详细教程

    [参考文献] http://www.jb51.net/article/65287.htm

  7. [PowerShell]get data from Ini File

    $filedata = @' app.name=Test App app.version=1.2 '@ $filedata | set-content appdata.txt $AppProps = ...

  8. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_对象的相等性和同一性

    [重写Equals注意的事项] 1. Equals 必须是自反的:--x.Equals(x)肯定为 true 2. Equals 必须是对称的:--x.Equals(y)肯定返回与y.Equals(x ...

  9. uva11361 特殊数的数量(数位dp)

    题目传送门 题目大意:给你一个n-m的区间,问你这个闭区间内的特殊数有几个,特殊数的要求是 数的本身 和 各位数字之和  mod k 等于0. 思路:刚接触数位dp,看了网上的题解,说用dp[i][j ...

  10. 线段树 区间更新(更新区间[x,y]的值,再求任意区间[x,y]的和)

    #1078 : 线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题 ...