一直想研究下安卓各种布局控件,FrameLayout是安卓最简单的界面布局,所以就从FrameLayout讲起。
1.属性。frameLayout继承ViewGroup,除了拥有ViewGroup的属性之外,只有一个layout_gravity属性。看它的内部静态类LayoutParams:
1 public static class LayoutParams extends MarginLayoutParams { 2 public int gravity = -1;//唯一的属性
2.绘制过程。首先,它会遍历所有子view,并且对每个子view进行measure,并记录下子view的最大宽高,作为自身的尺寸。在这个过程中,如果自身是不确定大小的模式,子view又是MATCH_PARENT属性的,就需要为这些子view重新测绘。
1 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 2 (。。。。。。) 3 4 int maxHeight = 0;//记录最大的宽高 5 6 int maxWidth = 0; 7 int childState = 0; 8 9 for (int i = 0; i < count; i++) { 10 final View child = getChildAt(i); 11 if (mMeasureAllChildren || child.getVisibility() != GONE) { 12 measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);//测绘所有子view 13 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 14 maxWidth = Math.max(maxWidth, 15 child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); 16 maxHeight = Math.max(maxHeight, 17 child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); 18 childState = combineMeasuredStates(childState, child.getMeasuredState()); 19 if (measureMatchParentChildren) { 20 if (lp.width == LayoutParams.MATCH_PARENT || 21 lp.height == LayoutParams.MATCH_PARENT) { 22 mMatchParentChildren.add(child);//保存需要重新测绘的子view 23 } 24 } 25 } 26 } 27 28 (。。。。。。) 29 if (count > 1) { 30 for (int i = 0; i < count; i++) { 31 <pre name="code" class="java" style="font-size: 13.3333px;"> (。。。。。。) 32 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);//重新测绘子view } } }
3.layout过程。FrameLayout对每个子view的layout过程是相同的。它遍历所有子view,通过子view的gravity属性进行xy轴偏移量的计算,最后调用child.layout()对子View进行布局。
1 void layoutChildren(int left, int top, int right, int bottom, 2 boolean forceLeftGravity) { 3 (。。。。。。) 4 5 for (int i = 0; i < count; i++) { 6 (。。。。。。) 7 8 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { 9 case Gravity.CENTER_HORIZONTAL: 10 childLeft = parentLeft + (parentRight - parentLeft - width) / 2 + 11 lp.leftMargin - lp.rightMargin; 12 break; 13 case Gravity.RIGHT: 14 if (!forceLeftGravity) { 15 childLeft = parentRight - width - lp.rightMargin; 16 break; 17 } 18 case Gravity.LEFT: 19 default: 20 childLeft = parentLeft + lp.leftMargin; 21 } 22 23 switch (verticalGravity) { 24 case Gravity.TOP: 25 childTop = parentTop + lp.topMargin; 26 break; 27 case Gravity.CENTER_VERTICAL: 28 childTop = parentTop + (parentBottom - parentTop - height) / 2 + 29 lp.topMargin - lp.bottomMargin; 30 break; 31 case Gravity.BOTTOM: 32 childTop = parentBottom - height - lp.bottomMargin; 33 break; 34 default: 35 childTop = parentTop + lp.topMargin; 36 } 37 38 child.layout(childLeft, childTop, childLeft + width, childTop + height); 39 } 40 } 41 }