Android 分析ScrollTo 和 ScrollBy

之前在面试一家大厂时问过我这个问题 :移动一个View,有几种办法,ScrollTo 和 ScrollBy区别是什么?

我特么没说出后者来。。。。擦,,,,,,遂研究学习下。。。。

首先,看下 ScrollTo 的源码,它是一个 view层的方法

翻译一下源码注释:

设置你的View的滑动位置,这会调用  onScrollChanged() 方法,然后你的View会被重新绘制

x : 滑动到X

y : 滑动到Y

 

Android 分析ScrollTo 和 ScrollBy_第1张图片

注意:这个方法里,每次都记录下,当前的偏移量  mScrollX 和 mScrollY 。

 

然后: mScrollX 和 mScrollY 呢? 

Android 分析ScrollTo 和 ScrollBy_第2张图片

 

很清晰,mScrollX 和 mScrollY  是View 内容 的偏移量,单位为像素。

而且每一次 调用ScrollTo () 移动,都会 保存当前 XY轴的偏移量。

 

划重点!!!           是   内容     的偏移量 

也就是用这个 ScrollTo(),并不会改变View本身的位置,只会改变View  内容  的位置

什么是内容呢?比如:TextView 里面的 text 就是内容,一个 ViewGroup  里面放了一个Button ,Button就是内容。

再比如我下面的例子:

ConstraintLayout 里面 嵌套一个 TextView ,通过 ConstraintLayout.ScrollTo()  即可移动 TextView 

在这之前,我先说一下,View的XY轴坐标是怎么定义的,如下图。

1>  左上角  为 (0,0)

2>  水平往右为正 反之为负。

3> 竖直往下为正,反之为负。

Android 分析ScrollTo 和 ScrollBy_第3张图片

废话少说,先看Demo:

activity_main.xml



    

    

    

    

    
        

    

 

MainActivity
package com.leo.dicaprio.myutilapp.ui

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.leo.dicaprio.myutilapp.R
import com.leo.dicaprio.myutilapp.thred.TestThread
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private var move: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button_down.setOnClickListener {
            cl_contain.scrollTo(-100, -100)
        }
        button_up.setOnClickListener {
            cl_contain.scrollTo(100, 100)
        }
        button_reset.setOnClickListener {
            cl_contain.scrollTo(0, 0)
        }
        button_by_down.setOnClickListener {
            cl_contain.scrollBy(-50, -50)
        }
    }
}

原始位置1

一开始,红色快为一个ViewGroup,绿色块为TextView,所以通过 ViewGroup.scroll()  移动的是 TextView(绿色)

这个原始的 坐标(0,0),后面的一些列通过 ScrollTo 或 ScrollBy移动内容,都是这个点为基准的。

Android 分析ScrollTo 和 ScrollBy_第4张图片

往右下移动 ScrollTo(-100,-100)

点击 -- 调用方法 ScrollTo(-100,-100) 看下效果图

Android 分析ScrollTo 和 ScrollBy_第5张图片

看到这,估计有人会有问题,不是负数就是往xy坐标反方向吗,

(-100,-100)按道理,应该是放  左上方去移动的,怎么会是右下方呢?

先别急,我后面会解释,反正先记住,传进去的参数是和坐标方向相反的

往左上方移动 ScrollTo(100,100)

点击 -- 调用方法 ScrollTo(100,100) 看下效果图

很明显,整个TextView是往左上去移动,此时左上角的坐标为(-100,-100)

注意,草绿色那一块我是为了显示超出父布局而补上去的,事实上是不存在的。

仅仅是想给出内容超出父布局的那一部分而已。

Android 分析ScrollTo 和 ScrollBy_第6张图片

回到初始位置 ScrollTo(0,0)

点击 -- 调用方法 ScrollTo(0,0) 看下效果图

很明显,和第一张效果图是一样的。

Android 分析ScrollTo 和 ScrollBy_第7张图片

 

到这里,ScrollTo(x,y)  基本上演示完。

下面说ScrollBy(x,y) 

看下其源码:

Android 分析ScrollTo 和 ScrollBy_第8张图片

简单明了。

都是把原来的偏移量  mScrollX 和 mScrollY  加上,然后再调用 ScrollTo()

所以:

1> ScrollBy是一个基于当前位置(mScrollX,mScrollY)的相对移动。

2> ScrollTo是一个基于原始位置坐标(0,0)的绝对移动。

 

多次 调用ScrollBy(-50,-50)

先恢复到原始位置,然后点击 -- 调用方法 ScrollTo(-50,-50) 看下效果图   往右下 移动了 50像素 第1次

Android 分析ScrollTo 和 ScrollBy_第9张图片

点击 -- 调用方法 ScrollTo(-50,-50) 看下效果图    第2次     在上图基础上 再往右下 移动了 50像素

Android 分析ScrollTo 和 ScrollBy_第10张图片

第3次....

第4次....

第5次....

第6次....

.......

知道第8次      

Android 分析ScrollTo 和 ScrollBy_第11张图片

所以  ScrollBy  是在 现在位置基础上去偏移,ScrollTo是基于原始位置的偏移。

 

 

为什么传进去的参数  和坐标轴方向相反的????

 

其实通过 onScrollChanged(去重新绘制)到最终的 到 invalidate()这个方法里

有这么这样的一个方法:   tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY)

绘制的目标指定位置是减去  你的偏移量。

所以和XY轴的方向是相反的。

具体跟踪的源码就不贴上来了,基本上记得这个理论即可。

 

最后说一下最开始的问题:

问题1:移动一个View,有几种办法?

1>   通过 ScrollTo  或 ScrollBy

2>   通过LayouParams  设置与父布局的间距

3>   通过动画

 

上面代码亲测没问题,如有问题请留言指正,谢谢!

 

 

 

 

你可能感兴趣的:(Android 分析ScrollTo 和 ScrollBy)