文档章节

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和OverScroller

一、ViewDragHelper 二、OverScroller 参考ScrollView

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

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

android-key
2016/11/23
3
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

没有更多内容

加载失败,请刷新页面

加载更多

python生成HTML报告

# -*- coding=utf-8 -*-# author=zyqimport timeclass Template(object): '''html报告''' HTML_TEMP=''' <!DOCTYPE html> <html lang="en"> <head......

小白兔_球球
10分钟前
1
0
模型融合资料汇总

https://blog.csdn.net/u012526003/article/details/79109418https://blog.csdn.net/willduan1/article/details/73618677https://blog.csdn.net/wstcjf/article/details/77989963?utm_so......

KYO4321
12分钟前
1
0
热更步骤

根据官方文档: http://docs.cocos.com/creator/manual/zh/advanced-topics/hot-update.html version_generator.js文件放到项目根目录下 注意步骤的顺序: 1.构建 2.根据构建目录运行下面命令...

Valiancer
12分钟前
1
0
小程序重写CheckBox样式

CheckBox /* 重写 checkbox 样式 *//* 未选中的 背景样式 */checkbox .wx-checkbox-input{ border-radius: 50%; width: 40rpx; height: 40rpx;}/* 选中后的 背景样式...

originDu
16分钟前
1
0
mysql自动安装脚本

[root@localhost_04 ~]# cat mysql.sh #!/bin/bash# "################检查本机安装mysql的基本条件########################"echo "Checking  user :"d=`id -u`if [ $d ......

芬野de博客
30分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部