Android把视图显示到屏幕上,从代码角度最终都是调用ViewGroup.addView方法,可以分为两类,一是初始化时添加视图,二是动态添加视图。
1. 从源码角度分析添加视图的流程,以下列出其中4个addView方法
public void addView(View child) {
addView(child, -1);
}
public void addView(View child, int index) {
LayoutParams params = child.getLayoutParams();
if (params == null) {
params = generateDefaultLayoutParams();
if (params == null) {
throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
}
}
addView(child, index, params);
}
public void addView(View child, int width, int height) {
final LayoutParams params = generateDefaultLayoutParams();
params.width = width;
params.height = height;
addView(child, -1, params);
}
public void addView(View child, LayoutParams params) {
addView(child, -1, params);
}
2. 以上4个addView方法其最终都会调用以下方法,实现具体操作
/**
* Adds a child view with the specified layout parameters.
*
* @param child the child view to add
* @param index the position at which to add the child
* @param params the layout parameters to set on the child
*/
public void addView(View child, int index, LayoutParams params) {
if (DBG ) {
System. out.println(this + " addView");
}
// 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
// 为什么调用invalidate还调用requestLayout?
requestLayout();
invalidate();
// 为什么先requestLayout, invalidate之后才向ViewGroup中添加View?
addViewInner(child, index, params, false);
}
3. 调用ViewGroup.addViewInner
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
// 此View是否已经添加
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 (!checkLayoutParams(params)) {
params = generateLayoutParams(params);
}
if (preventRequestLayout) {
child.mLayoutParams = params;
} else {
// 前面注释提到的,请求requestLayout
child.setLayoutParams(params);
}
// 如果传入-1,直接添加到最后
if (index < 0) {
index = mChildrenCount;
}
// 添加到ViewGroup
addInArray(child, index);
// tell our children
if (preventRequestLayout) {
child.assignParent( this);
} else {
// 指定添加view的父视图
child.mParent = this;
}
if (child.hasFocus()) {
requestChildFocus(child, child.findFocus());
}
AttachInfo ai = mAttachInfo;
if (ai != null) {
boolean lastKeepOn = ai.mKeepScreenOn;
ai.mKeepScreenOn = false;
// AttachInfo 与 View建立联系
child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
if (ai.mKeepScreenOn) {
needGlobalAttributesUpdate( true);
}
ai.mKeepScreenOn = lastKeepOn;
}
// 可以通过此监听器获得是否有新View被添加
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener .onChildViewAdded(this, child);
}
if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE ;
}
}
疑问:
1. 为什么调用invalidate还调用requestLayout?
2. 为什么先requestLayout, invalidate之后才向ViewGroup中添加View?