ViewGroup分配剪切区思路

作者: 暴走的Jacky | 来源:发表于2017-09-11 09:57 被阅读0次

     每个View从父视图拿到的剪切区的原点坐标都是View的视图坐标原点,剪切区的大小由View的布局(onLayout时确定)决定,剪切区的位置由View的布局和View的mScrollX\mScrollY决定。

View分配剪切区思路图

灰色矩形为最外层ViewGroup,不可滑动(mScrollX\mScrollY为0),蓝色矩形可滑动。


初始状态

       父视图在给子视图分配剪切区的时候(在2.3的源码中是View的dispatchdraw()方法),会根据子视图在onLayout时确定的位置和子视图mScrollX\mScrollY的值确定,确保子视图在onDraw(Canvas canvas)方法中拿到的canvas的坐标起点是子视图自身大小的坐标起点。所谓的draw操作只管将子视图本身画出来,而暂时不管其能否全部显示在屏幕上。此时子视图自身的坐标起点,可能在屏幕外(如上面右边的图),也可能在屏幕内。

在左图中,所有视图自身的大小,视图坐标原点,都是显示在屏幕上,你所看到的。

滑动后状态

     现在,手指在屏幕上向上滑动了100px的距离,正好把T1滑出屏幕外,那么此时mScrollY=100px。

     此时,灰色矩形拿到的剪切区仍然不变,因为他的onLayout值和mScrollX/mScrollY的值都没变化。至于蓝色矩形,他已经滑到了屏幕外100px,滑动并不会改变剪切区的大小,而只会改变其剪切区的位置,从而影响了他给子视图分配的剪切区的位置,所以导致了一部分子视图消失。

坐标变化图

视图坐标变化

     当灰色矩形为蓝色矩形分配剪切区时,他的canvas坐标原点在1,而蓝色矩形的视图坐标原点在2,那么怎样将canvas的坐标原点从1——>2呢?

     看看究竟他要考虑哪些参数,第一个参数,在onLayout时确定的mLeft,mTop,mRight,mBottom4个值,在图中我只标注了mLeft。这四个值确定剪切区的大小,因为无论你的视图有多大,如一张很大的Bitmap显示在ImageView中,无论你的Bitmap有多大,在Android手机上,给到你的ImageView的大小也撑破天只能是个全屏(比如1920x1080),这是从内存等性能问题上的考虑,因为java层其实就是数据的封装,如果你告诉底层我要2000x2000的剪切区(在底层对应着内存分配),这完全就是浪费内存和性能,你在底层分配的内存以及绘制的那部分,根本无法显示到屏幕上。所以,onLayout()存在的意义在于确定视图在屏幕上的位置,无论你的视图是多大,经过了onLayout方法之后,你在屏幕上的位置也就确定了。

     对父视图的canvas进行平移操作,canvas.translate(mLeft+mScrollX(0),mTop(0)+(-mScrollY)),这样canvas坐标就从1点平移到了2点(此时的canvas还是父视图的canvas,只是坐标点进行了平移)。视图坐标原点确定后,就要为子视图裁剪剪切区,调用canvas.clipRect(sx,sy,sx+(mRight-mLeft),sy+(mBottom-mTop),实际截切区的位置由sx和sy所确定,而剪切区的大小就是视图的布局大小)。

     网上有无数这样对ScrollX/ScrollY的理解,如"对于ViewGroup来说,调用scrollTo()是滑动子视图,对于View来说,调用scrollTo()是滑动其中的内容。"这样的解释对我来说毫无意义!!!

     在View体系中,scrollTo()调用之后,并不影响onMeasure()和onLayout()之后确定的值,只会影响mScrollX/mScrollY的值,从而影响子视图剪切区的分配。对于蓝色矩形来说,他的scroll值的改变影响了灰色矩形为他分配的剪切区,从而影响了蓝色矩形为所有子视图分配的剪切区。而蓝色矩形了布局是确定的,scroll值的改变不会影响该区域,只有剪切区在该区域内的子视图才会显示出来,其他的就隐藏了。

至于View内容的绘制,可以用数组的方式理解。

View的数组模型

     这样想,给TextView设置的文本字符最终会变成一个字符数组(如0-99),然而只有50-99下标的字符才可以显示在TextView中,其他的字符则"隐藏了"。对于ImageView,也可以用这样的理解,bitmap对象最终也会变成一个数组,ImageView的宽高是有限制的,而bitmap的大小则是没有限制的,如果你给ImageView设置src属性,那么只有一部分bitmap会显示,而设置backgroup属性,则bitmap会被压缩后全部显示。

     还有一种滑动的方式View.offsetTopAndBottom,他其实就是改变View的mTop和mBottom,但却不会调用onLayout。这样的滑动方式是改变子视图,如T1的内部参数,从而改变T1的剪切区位置,而其父视图不会受到任何影响。

     任何一种滑动,其本质就是改变View内的某种参数,让其在绘制的时候重新计算出View的剪切区,达到显示或隐藏得目的。上面的两种方式都规避的耗时的onLayout操作,所以滑动起来还是很流畅,应该避免用onLayout或LayoutParams值来进行滑动操作。

相关文章

  • ViewGroup分配剪切区思路

    每个View从父视图拿到的剪切区的原点坐标都是View的视图坐标原点,剪切区的大小由View的布局(onLay...

  • Java 堆/栈 GC相关

    一、Java程序运行时的内存分配策略 静态分配[静态存储区]/栈分配[栈区]/堆分配[堆区] 1)静态存储区...

  • vim命令整理之复制粘贴

    剪切,复制,粘贴 剪切 d命令不仅删除文本,它还“剪切”文本。每次我们使用d命令,删除的部分被复制到一个粘贴缓冲区...

  • 《JS原理、方法与实践》- canvas作图(二)- 组合、剪切

    组合与剪切 组合与剪切主要是对应多个图形来说的,组合指的是多个图形重叠时的组合方式,剪切是指使用路径来指定绘图的区...

  • C++之动态内存分配

    一、使用new分配内存 使用new动态分配的数组 栈区、堆区、全局区、常量区

  • C/C++变量的生命周期

    1、分配方式 静态分配: 静态区(全局区),分配全局变量、静态变量优先于main函数。 动态分配: (1)自动分配...

  • 【深入浅出-JVM】(8):TLAB

    概念 TLAB(Thread Local Allocation Buffer)线程本地分配缓冲区(线程私有分配区,...

  • Swift 中的内存分配情况与优化思路

    Allocation 内存分配 内存分配可以分为堆区栈区,在栈的内存分配速度要高于堆,结构体和类在堆栈分配是不同的...

  • 24物理内存管理下

    对于小的对象使用SLUB分配器进行分配kmem_cache 作为对象分配的缓存区(每次分配对象的时候都先到缓存区找...

  • C语言-变量

    1 变量的内存分配 内存可以分为五个区:栈区:局部变量,系统分配堆区:存放malloc函数分配出来的空间,程序员分...

网友评论

    本文标题:ViewGroup分配剪切区思路

    本文链接:https://www.haomeiwen.com/subject/oefnjxtx.html