900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Android源码解析:UI绘制流程之布局

Android源码解析:UI绘制流程之布局

时间:2020-06-11 14:58:49

相关推荐

Android源码解析:UI绘制流程之布局

带着问题看源码

上篇文章我们查看了UI绘制流程的测量方法,接着我们来看布局

同样从ViewRootImpl的performTraversals()方法中的performLayout()方法开始分析

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,int desiredWindowHeight) {mLayoutRequested = false;mScrollMayChange = true;mInLayout = true;final View host = mView;//...try {host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());mInLayout = false;//...}}//接着调用了View.layout()方法,(0,0)是左上角布局起始点,和测量好的View的大小View.layout()方法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;//调用setFrame()进行布局,返回值表示当前布局和之前的布局是否有改变boolean changed = isLayoutModeOptical(mParent) ?setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);//布局改变,则调用onLayout()方法if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {onLayout(changed, l, t, r, b);//...}} //View的onLayotu()方法是一个空实现protected void onLayout(boolean changed, int left, int top, int right, int bottom) {}复制代码

View的真正布局方法setFrame()

protected boolean setFrame(int left, int top, int right, int bottom) {boolean changed = false;//布局位置改变if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {changed = true;// Remember our drawn bitint drawn = mPrivateFlags & PFLAG_DRAWN;int oldWidth = mRight - mLeft;int oldHeight = mBottom - mTop;int newWidth = right - left;int newHeight = bottom - top;boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);// Invalidate our old positioninvalidate(sizeChanged);mLeft = left;mTop = top;mRight = right;mBottom = bottom;mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);mPrivateFlags |= PFLAG_HAS_BOUNDS;//控件宽高是否改变if (sizeChanged) {sizeChange(newWidth, newHeight, oldWidth, oldHeight);}if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) {mPrivateFlags |= PFLAG_DRAWN;invalidate(sizeChanged); //调用绘制方法// parent display list may need to be recreated based on a change in the bounds// of any childinvalidateParentCaches();}//...}return changed;}复制代码

我们看根控件DecorView的是如何进行控件布局的

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);getOutsets(mOutsets);//...}}//调用的是FrameLayout的onLayout()方法@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {//内部的实现方法是对子控件进行布局摆放layoutChildren(left, top, right, bottom, false /* no force left gravity */);}void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {final int count = getChildCount();final int parentLeft = getPaddingLeftWithForeground();final int parentRight = right - left - getPaddingRightWithForeground();final int parentTop = getPaddingTopWithForeground();final int parentBottom = bottom - top - getPaddingBottomWithForeground();for (int i = 0; i < count; i++) {final View child = getChildAt(i);if (child.getVisibility() != GONE) {final LayoutParams lp = (LayoutParams) child.getLayoutParams();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.CENTER_HORIZONTAL:childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +lp.leftMargin - lp.rightMargin;break;case Gravity.RIGHT:if (!forceLeftGravity) {childLeft = parentRight - width - lp.rightMargin;break;}case Gravity.LEFT: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;}//上面的内容是根据gravity求出每个子控件布局的上下左右位置,最后遍历调用子控件的layout()方法child.layout(childLeft, childTop, childLeft + width, childTop + height);}}}复制代码

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。