Android视图绘制流程之layout
2018-02-04 17:27
302 查看
借鉴自开发艺术
layout是view group用来确定子元素的位置的东西。
当ViewGroup的位置被确定后,它在onLayout中会遍历所有的子元素并调用其layout方法。
先看view的layout
先通过setFrame方法来设定View的4个顶点的位置,即初始化mLeft、mRight、mTop、mBottom,View的4个顶点的位置一旦确定,那么View在父容器的位置也确定了。接着会调用onLayout方法。这个方法是父容器确定子元素的位置,调用父view group的回调。
LinearLayout的onLayout方法
layoutVertical
这个方法会遍历所有的子元素并调用setChildFrame方法来为子元素确定对应的位置,其中childTop会逐渐增大,这就意味着后面的子元素会被放置在靠下的位置。所以他的一级级往下放不是空穴来风的,而是自己计算了下一个子元素的位置,并且防止在那个位置。
这个顺序是view的layout-自身的view的onLayout(如果有的话)-遍历view的layout...
这里才是获取了view实际的宽高
有两种情况,getHeight和getMeasureHeight会有不同
1.重写layout
2.测量过程中,有几次可能和得出的最终宽高不一致,不过最终来说,测量宽高和最终宽高还是一致的。
layout是view group用来确定子元素的位置的东西。
当ViewGroup的位置被确定后,它在onLayout中会遍历所有的子元素并调用其layout方法。
先看view的layout
@SuppressWarnings({"unchecked"}) public void layout(int l, int t, int r, int b) { if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } 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); if (shouldDrawRoundScrollbar()) { if(mRoundScrollbarRenderer == null) { mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); } } else { mRoundScrollbarRenderer = null; } 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; mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; notifyEnterOrExitForAutoFillIfNeeded(true); } }
先通过setFrame方法来设定View的4个顶点的位置,即初始化mLeft、mRight、mTop、mBottom,View的4个顶点的位置一旦确定,那么View在父容器的位置也确定了。接着会调用onLayout方法。这个方法是父容器确定子元素的位置,调用父view group的回调。
LinearLayout的onLayout方法
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (mOrientation == VERTICAL) { layoutVertical(l, t, r, b); } else { layoutHorizontal(l, t, r, b); } }
layoutVertical
final int count = getVirtualChildCount(); for (int i = 0; i < count; i++) { final View child = getVirtualChildAt(i); if (child == null) { childTop += measureNullChild(i); } else if (child.getVisibility() != GONE) { final int childWidth = child.getMeasuredWidth(); final int childHeight = child.getMeasuredHeight(); final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); ... if (hasDividerBeforeChildAt(i)) { childTop += mDividerHeight; } childTop += lp.topMargin; setChildFrame(child, childLeft, childTop + getLocationOffset(child), childWidth, childHeight); childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child); i += getChildrenSkipCount(child, i); } }
这个方法会遍历所有的子元素并调用setChildFrame方法来为子元素确定对应的位置,其中childTop会逐渐增大,这就意味着后面的子元素会被放置在靠下的位置。所以他的一级级往下放不是空穴来风的,而是自己计算了下一个子元素的位置,并且防止在那个位置。
private void setChildFrame(View child, int left, int top, int width, int height) { child.layout(left, top, left + width, top + height); }
这个顺序是view的layout-自身的view的onLayout(如果有的话)-遍历view的layout...
@ViewDebug.ExportedProperty(category = "layout") public final int getHeight() { return mBottom - mTop; }
这里才是获取了view实际的宽高
有两种情况,getHeight和getMeasureHeight会有不同
1.重写layout
@Override public void layout(int l, int t, int r, int b) { super.layout(l, t, r + 100, b + 100); }
2.测量过程中,有几次可能和得出的最终宽高不一致,不过最终来说,测量宽高和最终宽高还是一致的。
相关文章推荐
- Android视图的绘制流程(下)——View的Layout与Draw过程
- Android视图的绘制流程(下)——View的Layout与Draw过程
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android应用层View绘制流程之measure,layout,draw三步曲
- android视图学习---Android中View绘制流程以及invalidate()等相关方法分析
- 深入理解 Android 之 View 的绘制流程(三)_Layout
- ANDROID自定义视图——onLayout源码 流程 思路详解
- Android视图绘制流程完全解析(一)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二) ---站在巨人的肩膀上学习总结
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- 源码分析篇 - Android绘制流程(三)requestLayout()与invalidate()流程及Choroegrapher类分析
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析(二)
- Android视图绘制流程完全解析,深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析
- Android视图绘制流程完全解析,带你一步步深入了解View(二)