首先说下为什么分析FrameLayout .
……
因为他简单啊!! 哪像相对布局和线性布局 , 源码太长了…
大家也知道FrameLayout 的摆放规则 , 大部分使用是根据layout_gravity属性来控制摆放位置 , 如果你没有使用这个属性 , 默认就是放在左上角 , 并且最后添加的子View会显示在最上层 .
那么这篇文章从DecorView开始分析它的padding , margin等 , 这些值是怎么算到onMeasure()和onLayout()的 , 以及简单讲一下addView()方法和LayoutParam .
那么开始分析下
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<TextView
android:text="123"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</FrameLayout>
上篇文章中讲到 , Activity的setContentView()方法 , 执行完setContentView()方法后 , 这个布局已经添加到了DecorView上面了. 其实setContentView()方法里面也是调用了addView()方法将子View添加到父View上去的 , 再看addView()方法 , 他调用了requestLayout()方法 , 但是那么根据上篇文章讲到的requestLayout()方法会执行ViewRootImpl的requestLayout()接着调用performTraversal()方法来执行测量 , 摆放 , 绘制 .
但是!
在setContentView()的时候虽然调用了addView()方法 , 但是这时ViewRootImpl还没有实例化 , 它的实例化其实是在activity.attach()方法中 new 出来的 , 所以第一次的performTraversal()方法是在 handleResume()调用的 .
那么再重新屡一下DecorView在添加到Window之后他的第一次测量 、摆放和绘制 .
1. ActivityThread的handleResume()
2. 在handleResume()方法中调用了ViewRootImpl的setView()
3. ViewRootImpl的setView()方法中把decorView添加到了PhoneWindow
4. 接着调用了ViewRootImpl的requestLayout()
5. 最终他会在requestLayout()中调用performTraversals()之后 , 会使每个View执行他们的测量等方法
那么从DecorView开始看一下DecorView的 lp 是什么时候设置进去的并且值是什么
DecorView(Context context, int featureId, PhoneWindow window,
WindowManager.LayoutParams params) {
......
}
protected DecorView generateDecor(int featureId) {
......
return new DecorView(context, featureId, this, getAttributes());
}
可以看到DecorView构造函数的最后一个参数就是DecorView的LayoutParams
private final WindowManager.LayoutParams mWindowAttributes =
new WindowManager.LayoutParams();
public final WindowManager.LayoutParams getAttributes() {
return mWindowAttributes;
}
getAttributes()获得的其实就是mWindowAttributes
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
答案在WindowManager的LayoutParams的无参构造方法当中 , 也就是DecorView的lp宽高都是MATCH_PARENT .
接着看performTraversals()中的performMeasure()方法
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
private static int getRootMeasureSpec(int windowSize,