文档章节

View的滚动以及Scroller探究

飞越围墙
 飞越围墙
发布于 2016/11/13 17:34
字数 909
阅读 13
收藏 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和OverScroller

一、ViewDragHelper 二、OverScroller 参考ScrollView

GalaxyBruce
2016/06/17
48
0
源码解析---Scroller完全解析

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

android-key
2016/11/23
3
0
android 中文 api (64) —— Scroller

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

会飞柚子
2015/11/24
43
0
Android Scroller类与computeScroll方法的调用关系

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

IamOkay
2016/01/10
3K
3

没有更多内容

加载失败,请刷新页面

加载更多

windows 下 es安装ik后报错无法启动

1、没有安装分词器时可以正常启动 2、在安装分词器后就报错了 错误信息:Exception in thread "main" java.security.AccessControlException: access denied ("java.io.FilePermission" "D...

zhu_kai1
1分钟前
0
0
ReactNative入门教程-组件生命周期函数

1.组件实例化阶段 defaultProps: 设置组件的初始属性值,比如设置默认Color,width等,可以在通过this.props获取相应的值 constructor(props): 这里通过this.props可以获取defaultProps设置的...

凌宇之蓝
4分钟前
0
0
java使用bytebuddy动态生成带泛型的DTO

我这人文笔很low,喜欢直接贴代码,大家将就着看 //TODO 文字描述,回头有空再补上 package com.valsong.bytebuddy;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.Type...

ValSong
8分钟前
1
0
智能支付稳定性测试实战

本文根据美团高级测试开发工程师勋伟在美团第43期技术沙龙“美团金融千万级交易系统质量保障之路”的演讲整理而成。主要介绍了美团智能支付业务在稳定性方向遇到的挑战,并重点介绍QA在稳定性...

美团技术团队
10分钟前
0
0
Visual Studio Code 相关插件

Vue 开发工具:Visual Studio Code 相关插件: Chinese Auto Close Tag Auto Rename Tag Vetur ESLint Vue VS Code Extension Pack TortoiseSVN Debugger for Chrome...

华山猛男
12分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部