一直对View的滚动了解的不深,说明确了吧也能说出个所以然来,所以我就花了点时间做了一个小小的总结,言归正传,view的滑动分为下面三种:

1)View本身不滚动,指滚动View的内容,这也是View类提供的原始方法。通过scrollTo和ScrollBy方法来实现。

2)使用动画,让View来产生滚动效果

3)通过动态的改动LayoutParams的margin等属性让View来产生滚动

本篇博客就简单的分析一下第一种情况,同一时候本文最后还会简单的提供了一个样例:

View本身就提供了scrollBy和scrollTo方法,当中scrollBy方法又是调用了scrollTo方法:

    public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
//记录滚动的位置
 mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
} public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}

从方法的实现上就能够看出来两者的差别。scrollTo用mScrollX和mScrollY记录了滚动的偏移量。没有滚动的时候mScrollX和mScrollY皆为0,它表明了View的内容在x或者y的方向上滚动动的绝对滚动;而scrollBy在mScrollX或者mScrollY的基础上实现了相对滚动

在深入研究之前先说说为什么scrollTo和scrollBy滚动的是View的内容而非View本身。由于View在ViewGroup中的位置是由LayoutParams的margin等參数决定的。要想滚动View或者说要想改变View的位置仅仅须要改变LayoutParams的相关參数就能够。

可是scrollTo和scrollBy改变的仅仅是mScrollX和mScrollY的值,这两个值对于改变View在ViewGroup里面的位置是毫无关系的;这就排除了scrollTo或者scrollBy滚动的是View本身了,可是又有什么证据证明这两个方法滚动的是View的内容呢?且看这两个变量用在了什么地方就知道了。我们在View的draw方法里面发现了些许痕迹:

   if (background != null) {
final int scrollX = mScrollX;
final int scrollY = mScrollY; 省略了部分代码
if ((scrollX | scrollY) == 0) {
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}

我们知道一个View的显示须要经过測量Measure-->布局Layout-->绘制内容onDraw三个流程的。最后一个流程就是绘制View内容。在哪儿绘制?当然是在画布Canvas上面绘制!

上面的代码能够看出mScrollX和mScrollY这两个变量正式交给显示View内容的Canvase来操作的。所以我们说scrollTo或者scrollBy滚动的是View的内容。而不是改变View在parentView显示的位置关系。当然还须要注意的是假设是ViewGroup或者说parentView自己调动了scrollTo/scrollBy方法,那么viewGroup里面的childView的位置是能够改变的,由于childView本身就是ViewGroup里面的内容,(事实上ScrollView的滚动原理也是如此),这也是左右滑动屏幕实现的基本思路(可參考网上的这篇博客)。

事实上关于mScrollX和mSrcorllY的凝视就说明了这个问题:The offset, in pixels, by which the content of this view is scrolled。!

也就是说mScrollX/xScrollY是相对于“起始位置”在水平/竖直方向的偏移量;结合网上的一些博客资料能够得到例如以下图的关系

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

也就是说假设向左滚动,mScrollX为正值,反之为负值。假设向上滚动。mScrollY为正值,反之为负值!

尽管我们能够从源代码上看出scrollTo和scrollBy的差别,以下简单的通过样例来直观说一下二者的差别。以下是滚动之前的页面:

上下两个button点击事件的代码为:

/**记录上面button的点击次数**/
private int toCount = 0;
public void scrollToTest(View v) {
v.scrollTo(300, 0);
toCount++;
toTV.setText("" + toCount);
} /**记录羡慕button的点击次数**/
private int byCount = 0;
public void scrollByTest(View v) {
v.scrollBy(100, 0);
byCount ++;
byTV.setText(""+byCount);
}

也即是说上面的button每次点击时向左滚动300的距离,而以下的button每次点击向左滚动100的距离.执行效果例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" height="225" width="322">

执行效果发现调用scrollTo的时候不管点击了多少次都不会滚动了,仅仅是在点击第一次的时候才滚动了300.而scrollBy每次滚动在原来的基础上滚动了100,点击三次后达到了与scrollTo一样的效果。所以说scrollTo是一次性滚动到位的绝对滚动,而scrollBy是在前次滚动的基数上继续滚动,逐次滚动到位,是相对滚动!

当然调用scrollBy能够在前面滚动的基础上持续滚动下去,比方上面的那个样例继续点击以下的button。仍然会继续滚动。

写到这儿,突然想起了去年刚接触android的时候有一个关于TextView滚动次数的需求,让TextView跑马灯两次就停止滚动,当时水平有限,没有实现出来,如今倒是能够用srcollTo/scrollBy简单粗糙实现出来了。以下就说说这个控制滚动次数的自己定义TextView的滚动实现效果如图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

跑马灯效果图

上图为实现滚动的效果,切且滚动的位置用图A,图B...图G来表明方便下文的描写叙述。。详细执行效果能够文章最后的demo.以下详细先说说实现的核心原理:

1)获取TextView的字符串的宽度:

/**TextView字符串的宽度**/
private int textWidth;
private void measureTextWidth() {
Paint paint = this.getPaint();
String str = this.getText().toString();
textWidth = (int) paint.measureText(str);
} @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureTextWidth();
    }

2)让自己定义的TextView实现Runnable接口,在run方法里完毕滚动的控制,同一时候提供startScroll方法来开启滚动操作。

private int marqueeTemp =0;
    @Override
    public void run() {
        //已经完毕了指定的跑马灯次数
        if(marqueeTemp==marqueeTime) {
            return;
        }
        scrollBy(1,0); //实现跑马灯
        //注意是text字符串的宽度,而不是textView的宽度
        if (getScrollX() >= textWidth) {//假设一轮滚动结束
            marqueeTemp++;//累加滚动次数             //scrollBy实现方式
//            if(marqueeTemp==marqueeTime) {
//                scrollBy(-textWidth,0);
//            }else {
//                scrollBy(-this.getWidth()-textWidth,0);
//            }
            //scrollTo实现方式
            if(marqueeTemp==marqueeTime) {
                scrollTo(0,0);
            }else {
                scrollTo(-this.getWidth(),0);
            }
        
        }
//开启下次滚动
        postDelayed(this, 10);

上面的代码完毕了滚动的主要工作,请对照这上面的效果图来看。在滚动的时候也就是图B或者图E两个过程时候上面的代码调用了scrollBy(1,0)来逐步滚动1,直到滚动到图C或者图F的时候说明完毕了一次滚动。也即是代码中if(getScrollX() >= textWidth)条件成立。

此时滚动次数+1.。

在完毕一次滚动的时候。第二次滚动我们须要让TextView的字符串在图D所在的位置滚动,所以我们须要先让TextView的内容向右滚动到D的位置,然后在向左继续跑马灯。通过对scrollTo和ScrollBy的了解,这两种方式都能够让处于图C状态的内容滚动到图D状态位置:

前提正如前面所说向左移动的时候mScrollX>0.向右mScrollX<0;

1)scrollBy的实现方式:由于scrollBy是逐步滚动。对照着图C和图D,我们仅仅须要让scollBy的向右移动字符串的宽度+TextView的宽度就可以,即上面代码中的scrollBy(-this.getWidth()-textWidth,0);

2)scollTo的实现方式:一步到位的实现方式。由于从源代码上看scrollBy调用了scrollTo(mScroll+x,0),并且完毕一次滚动后mScroll=textWidth(字符串的宽度);所以我们直接调用scollTo(-this.getWidth(),0)就能够让TextView的内容滚动到图D位置。

通过1和2的解说,我们更是能够进一步的理解scrollBy和scrollTo的不同之处!!

!!

另外当滚动指定次数过后须要让TextView的内容回到初始位置,即上图中的图G位置,相同能够用srcollBy和scrollTo两种方式:

1)scrollBy方式:if(marqueeTemp==marqueeTime) {//完毕了指定次数的滚动

              scrollBy(-textWidth,0);

           }

2)scrollTo方式:if(marqueeTemp==marqueeTime) {

                scrollTo(0,0);

            }

原因应该不用多说了,到此为止。本篇博文正式结束,假设有错误的地方。欢迎批评指正,共同学习,最后附上博主的demo下载链接

关于滚动的补充说明见《此博客

View的滚动原理简单解析的更多相关文章

  1. 锐速与BBR的原理简单解析

    锐速与BBR的原理简单解析  4 前言 昨天,有一位朋友在我的文章下留言说,锐速和BBR不都是一样,是拥塞算法嘛.因为这方面需要讲的东西比较多,所以我还是专门水一篇文章吧. 锐速 参考资料: http ...

  2. foreach的使用原理简单解析

    数组可以foreach遍历,这个是在jdk1.5之前就可以的,我也不太清楚是怎么做到的. 后面的List,Set等的foreach都是实现Iterable接口,基于iterator()对象实现的.Fo ...

  3. View Animation 运行原理解析

    Android 平台目前提供了两大类动画,在 Android 3.0 之前,一大类是 View Animation,包括 Tween animation(补间动画),Frame animation(帧 ...

  4. 自己定义 View 基础和原理

    课程背景: 在 Android 提供的系统控件不能满足需求的情况下,往往须要自己开发自己定义 View 来满足需求,可是该怎样下手呢.本课程将带你进入自己定义 View 的开发过程,来了解它的一些原理 ...

  5. Android艺术开发探索第四章——View的工作原理(下)

    Android艺术开发探索第四章--View的工作原理(下) 我们上篇BB了这么多,这篇就多多少少要来点实战了,上篇主席叫我多点自己的理解,那我就多点真诚,少点套路了,老司机,开车吧! 我们这一篇就扯 ...

  6. android多线程-AsyncTask之工作原理深入解析(上)

    关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...

  7. view向上滚动

    之前本来是打算做TextView垂直向上滚动的,后来发现一位大神做得很好,https://github.com/sfsheng0322/MarqueeView 孙福生大神,然后自己要用到多个View向 ...

  8. GBDT算法原理深入解析

    GBDT算法原理深入解析 标签: 机器学习 集成学习 GBM GBDT XGBoost 梯度提升(Gradient boosting)是一种用于回归.分类和排序任务的机器学习技术,属于Boosting ...

  9. 梳理源码中 View 的工作原理

    欢迎Follow我的GitHub, 关注我的掘金. 在View的工作过程中, 执行三大流程完成显示, 测量(measure)流程, 布局(layout)流程, 绘制(draw)流程. 从perform ...

随机推荐

  1. JavaScript内存分配

    1.栈内存和堆内存 栈内存为自动分配的内存空间,由系统自动释放堆内存是动态分配的内存,大小不固定,也不会自动释放 js的值类型直接分配在栈内存中,引用类型分配在堆内存中引用类型变量保存的是引用类型的指 ...

  2. vue项目中使用阿里iconfont图标

    在上一篇文章中介绍了如何在vue项目中使用vue-awesome,如果你想了解,请移步<vue项目中使用vue-awesome> 这里介绍一下vue项目中如何使用阿里的iconfont图标 ...

  3. libc++abi.dylib`__cxa_throw: 使用[AVAudioPlayer play]会产生__cxa_throw异常

    libc++abi.dylib`__cxa_throw: 使用[AVAudioPlayer play]会产生__cxa_throw异常 开发中遇到一个奇怪的异常.我调用AVAudioPlayer pl ...

  4. 收集邮票(bzoj 1426)

    Description 有n种不同的邮票,皮皮想收集所有种类的邮票.唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n.但是由于凡凡也 ...

  5. .net开发工具集合

    原文发布时间为:2010-10-24 -- 来源于本人的百度文章 [由搬家工具导入] 原文出处:.NET Tools:Ten Must-Have Tools Every Developer Shoul ...

  6. 如何在win2003下安装sql2008[多次安装sql2008失败者必看]

    原文发布时间为:2010-11-02 -- 来源于本人的百度文章 [由搬家工具导入] 如何在win2003下安装sql2008[多次安装sql2008失败者必看] 1. 安装win2003,升级全部补 ...

  7. Qt5网络请求使用及WebRequest函数

    Qt5模拟curl进行HTTP的head请求, curl -I <url> : #include <QtCore> #include <QNetworkReply> ...

  8. 内存 : CL设置

    CL(CAS Latency):为CAS的延迟时间,这是纵向地址脉冲的反应时间,也是在一定频率下衡量支持不同规范的内存的重要标志之一. 内存负责向CPU提供运算所需的原始数据,而目前CPU运行速度超过 ...

  9. javascript解析机制——预解析

    JavaScript解析机制是什么? JavaScript解析过程分为两个阶段,一个是编译阶段,另外一个就是执行阶段. * 编译阶段         编译阶段就是我们常说的JavaScript预解析( ...

  10. OnClick五种事件处理

    (一)内部类 1,布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns: ...