//
/**
*View对象使用LayoutParams对象来告知其上层控件自己需要多少空间。
*基础LayoutParams类只是定义了这个view需要占用的宽度和高度。
* {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
* for a list of all child view attributes that this class supports.
*
* <p>
* 对于每一个维度,也就是对于宽度和高度,LayoutParams对象均可以使用以下参数:
* FILL_PARENT(api level 8及以上版本被更名为MATCH_PARENT),它表示这个view想要和包含它的控件在此维度上采用同样大小的尺寸
* WRAP_CONTENT,它表示这个view在此维度上采用可以包含它的内容的尺寸精确尺寸
* 有多个类继承于ViewGroup.LayoutParams类,比如,AbsoluteLayout类中定义了LayoutParams,它继承于ViewGroup.LayoutParams类
* Android中,直接继承于ViewGroup.LayoutParams类的有:ViewGroup.MarginLayoutParams,间接继承的类有:Linearlayout.LayoutParams,RelativeLayout.LayoutParams,FrameLayout.LayoutParams等等。</p>
*/
public static class LayoutParams
/*
* 添加一个view。如果这个view没有layout parameters参数定义,那么就采取默认参数。
*/
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);
}
使用view.getLayoutParams()获取params,如果params为空,就通过generateDefaultLayoutParams()的方式产生一个LayoutParams
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
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);
}
/**
* 添加一个指定的子view的布局参数。
*
* <p><strong>注释:</strong>不调用这个方法
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
* {@link #dispatchDraw(android.graphics.Canvas)} 或者相关方法.</p>
*/
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
requestLayout();强制此view向上一直requestLayout,使得view调用measure和layout
invalidate(true);重新draw此view。
addViewInner(child, index, params, false);
}
private void addViewInner(View child, int index, LayoutParams params,boolean preventRequestLayout) {
//当ViewGroup中的object改变时,mTransition用以处理动画效果,此对象的类是LayoutTransition
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);
}
//addView(view)时会检查view是不是具有ViewParent,如果有,就会抛出下面的异常,一个view只能有一个ViewParent。注:ViewParent是一个接口,ViewGroup实现了此接口。
if (child.getParent() != null) {
throw new IllegalStateException("The specified child already has a parent. " +
"You must call removeView() on the child's parent first.");
}
//这里的addChild并非是将view添加至ViewGroup中,这里是在处理动画效果
if (mTransition != null) {
mTransition.addChild(this, child);
}
//检查params是否为空
if (!checkLayoutParams(params)) {
params = generateLayoutParams(params);
}
//preventRequestLayout参数的含义是:是否禁止这个child去requestLayout(),原因是当使用直接赋值的时候,不会触发任何方法,但是当使用setLayoutParams()方法时,此方法中会去调用requestLayout()。不过View中的mLayoutParams参数被注解成了hide,无法在我们自定义的类中直接赋值。
if (preventRequestLayout) {
child.mLayoutParams = params;
} else {
child.setLayoutParams(params);//调用view中setLayoutParams
}
if (index < 0) {
index = mChildrenCount;
}
//addInArray()方法是将child添加到ViewGroup的mChildren对象中,mChildren是一个View[]类对象。
addInArray(child, index);
//assignParent()函数给child分配指定parent,并进行requestLayout(),采用preventRequestLayout进行判断,与上边的setLayoutParams()结合,可以保证child只调用一个requestLayout()
// tell our children
if (preventRequestLayout) {
child.assignParent(this);
} else {
child.mParent = this;
}
//焦点
if (child.hasFocus()) {
requestChildFocus(child, child.findFocus());
}
//和view所处环境相关的参数的设置
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();
}
//回调
onViewAdded(child);
if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
}
if (child.hasTransientState()) {
childHasTransientStateChanged(child, true);
}
}
clipChildren
定义是否限制子视图在它的范围内进行绘制。默认是true
clipToPadding
定义ViewGroup是否将剪切它的绘制界面并排除padding区域。默认是true
public abstract void bringChildToFront (View child)
把该视图置于其他所有子视图之上,如在FrameLayout中切换被叠放的视图。
getChildDrawingOrder
返回当前迭代子视图的索引.就是说 获取当前正在绘制的视图索引. 如果需要改变ViewGroup子视图绘制的顺序,则需要重载这个方法.并且需要先调用 setChildrenDrawingOrderEnabled(boolean)
方法来启用子视图排序功能.
isChildrenDrawingOrderEnabled()
获取当前这个ViewGroup是否是按照顺序进行绘制的
getDescendantFocusability
android:descendantFocusability
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
focusableViewAvailable (View v)
通知父类一个新的并且能够取得焦点的子视图可以使用了。用于处理从没有可取得焦点的视图到出现第一个可以取得焦点的视图的转变。
参数 v 新出现的可以取得焦点的视图
---------在我们的项目中因为移出添加比较大已经实例化的Layout ,多次后界面上的按钮出现无法点击情况。如briefcase 中"create new folder"