文档章节

View的滚动以及Scroller探究

飞越围墙
 飞越围墙
发布于 2016/11/13 17:34
字数 909
阅读 12
收藏 0

前言

说来惭愧,Android开发好几年,对于滚动仍然一无所知,一般自定义view如果要滚动就是直接把ScrollView也打包进去,也能完成既定需求.在公司项目中有一个环形菜单控件一直点卡卡的,看代码是响应触摸事件然后改变LayoutParams,再重绘实现的,当时想这个也相当于"滑动"呀,是不是可以用Scroller来实现(后来发现太天真).

Scroller

Scroller是一个滚动的辅助类,它负责告诉你某一时刻滚动到了那个位置以及滚动有没有完成. 下面是几个主要的方法

  • void startScroll(int startX, int startY, int dx, int dy, int duration) 开始滚动,Scroller纪录开始的位置,要滚动的距离,滚动时间,以及滚动开始的时刻
  • boolean computeScrollOffset() 计算滚动距离,Scroller计算调用这个方法的时刻需要滚动到的位置,顺便返回是否已经滚动到位了(即结束了)
  • int getCurrX() 方法调用时刻scroller的X位置
  • int getCurrY() 方法调用时刻scroller的Y位置

假如:我自定义View的内容要移动水平移动50,垂直移动30,是怎样进行的呢

  1. 先startScroll,纪录下要从0,0,X滚动50,Y滚动30,滚动时间250ms
  2. 调用computeScrollOffset()计算一下从startScroll开始到现在过了多少时间,按速度应该到哪个位置了.
  3. 用getCurrX()和getCurrY()拿到计算出来的位置,把View的内容移到那个位置
  4. 要是第2步的computeScrollOffset()返回true,则再调用第2步,循环往复,直到返回false,说明移动到位了,滚动结束

View的滚动

View的滚动就是按上面的原理进行的, 首先我们通过事件(滑动,点击,代码)触发滚动,调用startScroll,然后调用postInvalidate()重绘View, 重绘会调用View.computeScroll(),这个方法里调用上面说的第2-3步(这里最后移动内容是调用的View.scrollTo(x,y)), 而scrollTo又会触发View的重绘,循环往复,直到滚动完成.

真正移动view的内容的动作是View.scrollTo(x,y),通过分析源代码发现是通过移动canvas来实现的.

代码比文字简单100倍,

测试代码片段:http://git.oschina.net/sun141421/laj4tp78vcr12usw36ghd69.code.git

以下是对View的源代码不严谨分析(基于Android-24)

View.scrollTo(x,y)

  /**
     * Set the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the x position to scroll to
     * @param y the y position to scroll to
     */
    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();
            }
        }
    }

可以看出它只是赋值了mScrollX mScrollY,并调用postInvalidateOnAnimation()引起View树的重绘, 父控件通过调用viewGroup.drawChild()重绘子控件

    /**
     * Draw one child of this View Group. This method is responsible for getting
     * the canvas in the right state. This includes clipping, translating so
     * that the child's scrolled origin is at 0, 0, and applying any animation
     * transformations.
     *
     * @param canvas The canvas on which to draw the child
     * @param child Who to draw
     * @param drawingTime The time at which draw is occurring
     * @return True if an invalidate() was issued
     */
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }

子控件的 child.draw(canvas, this, drawingTime)中调用了updateDisplayListIfDirty();

     /**
     * This method is called by ViewGroup.drawChild() to have each child view draw itself.
     *
     * This is where the View specializes rendering behavior based on layer type,
     * and hardware acceleration.
     */
    boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        ....
        renderNode = updateDisplayListIfDirty();
        ....            
    }

在updateDisplayListIfDirty()中有关键的几行,

    /**
     * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported)
     * @hide
     */
    @NonNull
    public RenderNode updateDisplayListIfDirty() {
        ....
         computeScroll();

         canvas.translate(-mScrollX, -mScrollY);
        ....  
       draw(canvas);
        ....
            
    }

它先调用 computeScroll()计算好mScrollX,mScrollY然后 canvas.translate,最后draw

© 著作权归作者所有

共有 人打赏支持
飞越围墙
粉丝 1
博文 2
码字总数 909
作品 0
广州
程序员
weex scroller滚动的小烦恼

【背景】 前几天的需求开发中,需要完成这样一个功能: 这还不简单?一个横向滚动的tag选择功能。一个横向scroller搞定问题。 但是做为一个对自己有“要求”的程序员,怎么可能会接受一个死气...

bkaq
07/10
0
0
源码解析---Scroller完全解析

Scroller完全解析 1.概述 Scroller是一个专门用于处理滚动效果的工具类,可能在大多数情况下,我们直接使用Scroller的场景并不多,但是很多大家所熟知的控件在内部都是使用Scroller来实现的,...

android-key
2016/11/23
3
0
Scroller和OverScroller

一、ViewDragHelper 二、OverScroller 参考ScrollView

GalaxyBruce
2016/06/17
48
0
Android Scroller类与computeScroll方法的调用关系

Android ViewGroup中的Scroller与computeScroll的有什么关系? 答:没有直接的关系 知道了答案,是不是意味着下文就没必要看了,如果说对ViewGroup自定义控件不感兴趣,可以不用看了。 1.Sc...

IamOkay
2016/01/10
3K
3
android 中文 api (64) —— Scroller

前言   本章内容是 android.widget.Scroller,版本为Android 2.3 r1,翻译来自"pengyouhong",再次感谢"pengyouhong"!期待你一起参与Android中文API的翻译,联系我over140@gmail.com。 声...

会飞柚子
2015/11/24
43
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

angular 解决其他电脑不能访问的问题。

ng serve --host 0.0.0.0 --disable-host-check

miaojiangmin
今天
1
0
优酷视频文件怎么转换格式

  以前在优酷上下载视频都只是在手机上观看,但随着科技的发展,对于视频的要求也逐渐增多,不再只是观看视频那么简单,在精彩的部分还会将其单独分割出来,然后进行视频剪辑,可以做出我们...

萤火的萤火
今天
0
0
数据结构:散列

在一个数据结构中查找key元素,用顺序查找、二分查找都需要经过一系列关键之比较才能查找到结果,平均查找长度与数据量有关,元素越多比较次数就越多。 如果根据元素的关键字就能知道元素的存...

京一
今天
0
0
Apache RocketMQ 正式开源分布式事务消息

近日,Apache RocketMQ 社区正式发布4.3版本。此次发布不仅包括提升性能,减少内存使用等原有特性增强,还修复了部分社区提出的若干问题,更重要的是该版本开源了社区最为关心的分布式事务消...

阿里云云栖社区
今天
30
0
使用JavaScript和MQTT开发物联网应用

如果说Java和C#哪个是最好的开发语言,无疑会挑起程序员之间的相互怒怼,那如果说JavaScript是动态性最好的语言,相信大家都不会有太大的争议。随着越来越多的硬件平台和开发板开始支持JavaS...

少年不搬砖老大徒伤悲
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部