[Android FrameWork 6.0源码学习] ViewGroup的addView函数分析
Android中整个的View的组装是采用组合模式。
ViewGroup就相当与树根,各种Layout就相当于枝干,各种子View,就相当于树叶。
至于View类。我们就当它是个种子吧。哈哈!
ViewGroup属于树根,可以生长数很多枝干(继承自定义Layout)而枝干上有可以长出很多叶子(TextView,ImageVIew......)
好,闲话少叙,接下来步入正题!
首先,关于View的操作方法,被定义在一个叫做ViewManager的接口中,接口中还有两个方法,分别是移除和更新,这次主要分析addView
public interface ViewManager
{
/**
* Assign the passed LayoutParams to the passed View and add the view to the window.
* <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
* errors, such as adding a second view to a window without removing the first view.
* <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
* secondary {@link Display} and the specified display can't be found
* (see {@link android.app.Presentation}).
* @param view The view to be added to this window.
* @param params The LayoutParams to assign to view.
*/
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view)
}
addView在ViewGroup中实现,接下来贴出代码进行分析
public void addView(View child, LayoutParams params) {
addView(child, -1, params);
}
这个方法中调用了自身的addView方法,并且多传递了一个-1,这个-1是View的索引,要插入的位置
public void addView(View child, int index, LayoutParams params) {
if (DBG) {
System.out.println(this + " addView");
}
if (child == null) {
throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
}
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
requestLayout();
invalidate(true);
addViewInner(child, index, params, false);
}
这个方法先是重绘了一下布局,然后调用了addViewInner(child, index, params, false);方法,来把View插入到相应的位置
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
if (mTransition != null) {
// Don't prevent other add transitions from completing, but cancel remove
// transitions to let them complete the process before we add to the container
mTransition.cancel(LayoutTransition.DISAPPEARING);
}
if (child.getParent() != null) {
throw new IllegalStateException("The specified child already has a parent. " +
"You must call removeView() on the child's parent first.");
}
if (mTransition != null) {
mTransition.addChild(this, child);
}
if (!checkLayoutParams(params)) {
params = generateLayoutParams(params);
}
if (preventRequestLayout) {
child.mLayoutParams = params;
} else {
child.setLayoutParams(params);
}
if (index < 0) {
index = mChildrenCount;
}
//ViewGroup用一个View类型的数组去维护下边的子view,这个方法就是把view添加到响应的位置上
addInArray(child, index);
//绑定插入的view的父容器为当前group
// tell our children
if (preventRequestLayout) {
child.assignParent(this);
} else {
child.mParent = this;
}
if (child.hasFocus()) {
requestChildFocus(child, child.findFocus());
}
AttachInfo ai = mAttachInfo;
if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
boolean lastKeepOn = ai.mKeepScreenOn;
ai.mKeepScreenOn = false;
child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
if (ai.mKeepScreenOn) {
needGlobalAttributesUpdate(true);
}
ai.mKeepScreenOn = lastKeepOn;
}
if (child.isLayoutDirectionInherited()) {
child.resetRtlProperties();
}
dispatchViewAdded(child);
if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
}
if (child.hasTransientState()) {
childHasTransientStateChanged(child, true);
}
if (child.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
if (mTransientIndices != null) {
final int transientCount = mTransientIndices.size();
for (int i = 0; i < transientCount; ++i) {
final int oldIndex = mTransientIndices.get(i);
if (index <= oldIndex) {
mTransientIndices.set(i, oldIndex + 1);
}
}
}
}
这个方法先检查一下LayoutParams,看看插入的该view是否存在长宽,如果没有就生成一个默认的LayoutParams
然后判断index是否小于0,小于0就赋值为当前容器中的个数,代表插入到最后一项
随后就调用addInArray方法,来插入View到当前ViewGroup中,插入完成后给该view绑定一下父容器(getParent的值)
随后就是一些焦点,监听的分发,我们仔细分析一下插入方法就好了,就是addInArray
private void addInArray(View child, int index) {
View[] children = mChildren;
final int count = mChildrenCount;
final int size = children.length;
if (index == count) {
if (size == count) {
mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
System.arraycopy(children, 0, mChildren, 0, size);
children = mChildren;
}
children[mChildrenCount++] = child;
} else if (index < count) {
if (size == count) {
mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
System.arraycopy(children, 0, mChildren, 0, index);
System.arraycopy(children, index, mChildren, index + 1, count - index);
children = mChildren;
} else {
System.arraycopy(children, index, children, index + 1, count - index);
}
children[index] = child;
mChildrenCount++;
if (mLastTouchDownIndex >= index) {
mLastTouchDownIndex++;
}
} else {
throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
}
}
mChildren是ViewGroup中的一个View类型的数组,里边存放了该Group下的所有子View
ARRAY_CAPACITY_INCREMENT这个常量的值是12
首先判断一下mChildren的位置还是否充足,不充足就继续扩充12个位置出来,copy源数组内容进到新数组里,然后再把本次要添加的view放到最后
如果index比count小,说明是插入操作,也是先判断位置是否充足,不充足就扩充并且copy到index处,然后在把剩下的copy到index+1到末尾
这样就把index位置空了出来。就完成了插入操作
插入完成后,系统会重绘界面,你就可以看到你插入的view了。
addView这个方法就分析完了,有什么疑问就可以指出来,错误也一样。共同学习共同进步。
[Android FrameWork 6.0源码学习] ViewGroup的addView函数分析的更多相关文章
- [Android FrameWork 6.0源码学习] View的重绘过程之WindowManager的addView方法
博客首页:http://www.cnblogs.com/kezhuang/p/关于Activity的contentView的构建过程,我在我的博客中已经分析过了,不了解的可以去看一下<[Andr ...
- [Android FrameWork 6.0源码学习] LayoutInflater 类分析
LayoutInflater是用来解析XML布局文件,然后生成对象的ViewTree的工具类.是这个工具类的存在,才能让我们写起Layout来那么省劲. 我们接下来进去刨析,看看里边的奥秘 //调用i ...
- [Android FrameWork 6.0源码学习] View的重绘过程之Draw
View绘制的三部曲,测量,布局,绘画现在我们分析绘画部分测量和布局 在前两篇文章中已经分析过了.不了解的可以去我的博客里找一下 下面进入正题,开始分析调用以及函数原理 private void pe ...
- [Android FrameWork 6.0源码学习] View的重绘过程
View绘制的三部曲, 测量,布局,绘画今天我们分析测量过程 view的测量是从ViewRootImpl发起的,View需要重绘,都是发送请求给ViewRootImpl,然后他组织重绘在重绘的过程中 ...
- [Android FrameWork 6.0源码学习] Window窗口类分析
了解这一章节,需要先了解LayoutInflater这个工具类,我以前分析过:http://www.cnblogs.com/kezhuang/p/6978783.html Window是Activit ...
- [Android FrameWork 6.0源码学习] View的重绘过程之Layout
View绘制的三部曲,测量,布局,绘画现在我们分析布局部分测量部分在上篇文章中已经分析过了.不了解的可以去我的博客里找一下 View的布局和测量一样,都是从ViewRootImpl中发起,ViewRo ...
- [Android FrameWork 6.0源码学习] View的重绘ViewRootImpl的setView方法
博客首页:http://www.cnblogs.com/kezhuang/p/ 本篇文章来分析一下WindowManager的后续工作,也就是ViewRootImpl的setView函数的工作 /i* ...
- [Android framework学习] ViewGroup的addView函数分析
博客首页:http://www.cnblogs.com/kezhuang/p/ Android中整个的View的组装是采用组合模式. ViewGroup就相当与树根,各种Layout就相当于枝干,各种 ...
- 【Spark2.0源码学习】-1.概述
Spark作为当前主流的分布式计算框架,其高效性.通用性.易用性使其得到广泛的关注,本系列博客不会介绍其原理.安装与使用相关知识,将会从源码角度进行深度分析,理解其背后的设计精髓,以便后续 ...
随机推荐
- linux系统管理--进程管理
这两天一直维护公司的服务器,主要对进程管理和linux工作管理,把一些零散的知识整理一下,书归正传~ 什么进程? 以下是百度给的解释的进程,说实话,云里雾里的,其实linux进程和windows进程 ...
- PHP中的运算符
一.算术运算符 运算符 名称 描述 实例 结果 x + y 加 x 和 y 的和 2 + 2 4 x - y 减 x 和 y 的差 5 - 2 3 x * y 乘 x 和 y 的积 5 * 2 1 ...
- 9、JcomboBox下拉框事件监听
9.JcomboBox下拉框事件监听 JComboBox()的事件监听类ItemListener.其范例代码如下: import java.awt.*; import java.awt.event.* ...
- 013 session_flush
在hibernate中也存在flush这个功能,在默认的情况下session.commit()之前时,其实执行了一个flush命令. Session.flush功能: ②理缓存: ②执行sql(确定是 ...
- 【.net 深呼吸】通过标准输入/输出流来完成进程间通信
实现进程之间煲电话粥的方式,有好几种,比如,你可以用这些方案: 1.使用socket来传递.这个好像很无聊,本地进程之间也用socket?不过,通过本机回环网络确实可以进程之间通信. 2.WCF,与上 ...
- [原创]CentOS下Mysql双机互为备份
一.环境: 1.安装Centos-6.5-x64位系统的机器两台: host1:192.168.2.3 host2:192.168.2.4 (互相能ping通) 2.安装Mysql. 命令:Yum ...
- (转)Java 读写Properties配置文件
原文:http://www.cnblogs.com/xudong-bupt/p/3758136.html 1.Properties类与Properties配置文件 Properties类继承自Hash ...
- 一天搞定CSS:文本text--05
1.文本体系 2.文本各属性取值 说明: 每一个属性后面的分支是属性值,以及对属性值的说明. 比如text-align- - - -有3个取值:left,center,right 3.空格大小 4.代 ...
- mysql之 mysql 5.6不停机双主一从搭建(活跃双主一从基于日志点复制)
环境说明:版本 version 5.6.25-log 主1库ip: 10.219.24.25主2库ip: 10.219.24.22从1库ip:10.219.24.26os 版本: centos 6.7 ...
- 【Selenium】Selenium1
一.Selenium1组件 (1)Selenium服务器,负责启动关闭浏览器:解释和运行从测试程序中传来的Selenium命令:HTTP代理:获取和验证在浏览器和被测试的应用程序之间的传递的HTTP消 ...