【Android】View绘制过程分析之layout
2014-02-22 00:25
399 查看
续前文“【Android】View绘制过程分析之measure”,继续分析View的绘制过程。
本文分析第2阶段,分析过程的注释标记在以下代码中。
/**
* 此方法来给此View及它的子View分配大小和位置,
* 子类不要覆写此方法,而覆写onLayout(boolean, int, int, int, int)方法即可
* 左上右下4个参数,表示此View相对于父View的位置
*/
public void layout(int l, int t, int r, int b) {
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
//我们通过这个方法来分配大小和位置
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList<OnLayoutChangeListener> listenersCopy =
(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
int numListeners = listenersCopy.size();
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
}
/**
* 此方法给子View分配大小和位置。
* 应该做的事情:遍历子View, 调用子View的layout(int, int, int,int)方法给子View分配大小和位置
* 左上右下4个参数,表示此View相对于父View的位置
*/
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
/**
* View类中空实现这个方法,留给子类去实现。
* 下面看一下FrameLayout类的实现代码。
*/
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final int count = getChildCount();
/**
* 下面4个方法:
* 若不考虑padding,则以下4个值应为:
* parentLeft = 0; parentRight = right-left; parentTop = 0; parentBottom = bottom - top;
* 前面说到onLayout传入的左上右下4个参数是此View相对于父View的位置,那么right-left即求得此View所占的宽度,bottom-top即求得此View所点的高度
* 而这4个值构成的矩形范围,正是此View的占用范围
*/
final int parentLeft = getPaddingLeftWithForeground();
final int parentRight = right - left - getPaddingRightWithForeground();
final int parentTop = getPaddingTopWithForeground();
final int parentBottom = bottom - top - getPaddingBottomWithForeground();
mForegroundBoundsChanged = true;
//遍历子View,计算子View的位置
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
//子View的大小在onMeasure(int, int)方法中已经计算得到
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = DEFAULT_CHILD_GRAVITY;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
childLeft = parentLeft + lp.leftMargin;
break;
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = parentRight - width - lp.rightMargin;
break;
default:
childLeft = parentLeft + lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
//调用子View的layout(int,int,int,int), 上面计算得到的4个值确定了子View的位置范围
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
@容新华技术博客 - http://blog.csdn.net/rongxinhua - 原创文章,转载请注明出处
本文分析第2阶段,分析过程的注释标记在以下代码中。
/**
* 此方法来给此View及它的子View分配大小和位置,
* 子类不要覆写此方法,而覆写onLayout(boolean, int, int, int, int)方法即可
* 左上右下4个参数,表示此View相对于父View的位置
*/
public void layout(int l, int t, int r, int b) {
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
//我们通过这个方法来分配大小和位置
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList<OnLayoutChangeListener> listenersCopy =
(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
int numListeners = listenersCopy.size();
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
}
/**
* 此方法给子View分配大小和位置。
* 应该做的事情:遍历子View, 调用子View的layout(int, int, int,int)方法给子View分配大小和位置
* 左上右下4个参数,表示此View相对于父View的位置
*/
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
/**
* View类中空实现这个方法,留给子类去实现。
* 下面看一下FrameLayout类的实现代码。
*/
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final int count = getChildCount();
/**
* 下面4个方法:
* 若不考虑padding,则以下4个值应为:
* parentLeft = 0; parentRight = right-left; parentTop = 0; parentBottom = bottom - top;
* 前面说到onLayout传入的左上右下4个参数是此View相对于父View的位置,那么right-left即求得此View所占的宽度,bottom-top即求得此View所点的高度
* 而这4个值构成的矩形范围,正是此View的占用范围
*/
final int parentLeft = getPaddingLeftWithForeground();
final int parentRight = right - left - getPaddingRightWithForeground();
final int parentTop = getPaddingTopWithForeground();
final int parentBottom = bottom - top - getPaddingBottomWithForeground();
mForegroundBoundsChanged = true;
//遍历子View,计算子View的位置
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
//子View的大小在onMeasure(int, int)方法中已经计算得到
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = DEFAULT_CHILD_GRAVITY;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
childLeft = parentLeft + lp.leftMargin;
break;
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = parentRight - width - lp.rightMargin;
break;
default:
childLeft = parentLeft + lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
//调用子View的layout(int,int,int,int), 上面计算得到的4个值确定了子View的位置范围
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
@容新华技术博客 - http://blog.csdn.net/rongxinhua - 原创文章,转载请注明出处
相关文章推荐
- Android视图的绘制流程(下)——View的Layout与Draw过程
- 【Android View绘制之旅】Layout过程
- android应用程序窗口框架学习(2)-view绘制流程源代码解析-setContentView与LayoutInflater加载解析机制源码分析
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析(下)
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析(上)
- Android中View和ViewGroup的measure和layout过程分析
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- Android中将xml布局文件转换为View树的过程分析(下)-- LayoutInflater源码分析 - xiaoweiz
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- Android中将xml布局文件转化为View树的过程分析(下)-- LayoutInflater源码分析
- Android视图的绘制流程(下)——View的Layout与Draw过程
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- 【Android】View绘制过程分析之measure
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起(写的很好,这个不是从启动app说的,说的是UI是怎么绘制的)
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- android中View绘制过程分析
- 【Android】View绘制过程分析之draw