从本篇开始,我们会仔细阅读每一句源码,逐行弄清楚代码的详细含义。
本篇会通过getChildCount()讲到ViewGroup在内部如何储存和管理child view。
getChildCount()和mChildCount
先来看第一句
int count = getChildCount();
view/ViewGroup.java
public int getChildCount() {
return mChildrenCount;
}
这个变量的
定义是
view/ViewGroup.java
private int mChildrenCount;
初始化是在initViewGroup中,由ViewGroup三个构建函数调用
view/ViewGroup.java
constructor() -> initViewGroup() {
...
mChildrenCount = 0;
...
}
mChildrenCount的值受到以下几个函数的影响,参数简写为(,),下同。
view/ViewGroup.java
addInArray(,) // 增加
removeFromArray(,) // 减少
removeAllViewsInLayout(,) // 归零
这里的Array是指mChildren,装着所有child view定义为
view/ViewGroup.java
private View[] mChildren;
到此为止我们可能认为getChildCount()返回的是mChildren数列的大小。
但是真的是这样的吗?我们继续看这几个函数
AddInArray代码分析(数字对应图片数字)
1. 在末尾插入view
2. 不在末尾插入view
3. index太大,错误
4. size == count,如果mChildren的长度和mChildCount是一致的话?什么,他们不一致?是的。为了效率,mChildren一次会增加ARRAY_CAPACITY_INCREMENT大小。children变量暂存了之前的mChildren的值,增大mChildren之后,做了拷贝。
5. if分支,和上面一样,只不过分了两次拷贝,中间留出了index的位置以便后面插入。else分支,index之前的值不动,index开始移动到index+1的位置,也是留出index以便插入。
6. 插入view,增大计数。mLastTouchDownIndex是用来debug的,我们主要是读FrameLayout就不深究了。
AddInArray调用分析(数字对应图片数字)
addInArray是私有函数,我们来看看哪些函数会调用它,我们平时写程序的时候,是否也会隐性调用(当然 - _=)
protected attachViewToParent(,) // view被贴到parent上的时候
public bringChildToFront(,) // child view交换位置,会有删除和增加
private addViewInner(,) // 这个是私有函数,我们继续看
而调用addViewInner的函数是
public addView(,) // 这个常用到,动态增加view
protected addViewInLayout(,) // 这个比较少,注释说一般在onLayout里使用,可以不requestLayout,坑。
接下来看第二个函数removeFromArray(,)
private removeFromArray(int index) // 删除某个位置上的view
private removeFromArray(int start, int count) // 从某个位置开始,连续删除几个view,范围[start, end)
removeFromArray第一个版本代码分析(数字对应图片数字)
1. mTransitioningViews 是正在动画中的view,如果不是正在动画的话,就删除解除parent view关系,不然留给其他方法处理(endViewTransition)
2. 在末尾就直接删掉,不在末尾做一个拷贝,把index+1位置起的数据前移一格到index位置,如果index超出[0,count)的范围报错。前两者要减少mChildCount。
removeFromArray第二个版本代码分析(数字对应图片数字)
1. 把旧children和count复制一份,确保start和end在合理范围内,如果start就是end不做任何操作,直接返回。
2. 如果删除后半截,逐个解除parent,删除。
3. 如果删除中间半截,先解除这些view的parent,然后把从end开始的部分拷贝到start的位置。然后逐个把后面多出来的部分删除。
4. 把mChildCount减少,注意这里及以上范围都是这里范围是[start, end)
接下来看看那些函数调用了removeFromArray
protected detachViewFromParent(,) // 有两个版本分别对应删除某个view和删除连续的几个view
public bringChildToFront() // 见上
private removeViewInternal(,) // 两个版本,实际进行view的删除工作, 让removeFromArray删除view模型,自己处理动画,焦点等等。不详述。
而removeViewInternal被如下函数调用
public removeView() // 删除某个view
public removeViewInLayout() // layout版本的删除view,坑
public removeViewAt() // 删除某个index的view
removeAllViewsInLayout
这个比较复杂,打算放到layout系列讲。
总结一下ViewGroup管理child view的方法
----------------------------------------------------------------------------
FrameLayout measure过程源码Log全解析系列