• Android 布局浅析


    Android布局绘制流程:

    根节点 noodview 递归调用每一级子view 的 Mesure 进行测量

    然后

    从根节点 noodview 递归调用每一级子view 的 layout 方法,把测量过程得出的子view的位置和size进行传递给子view ,然后子view保存参数

    测量是动态化,是需要根view和子view

    首先nood view 根节点,在自己的measure 中,根据xml布局中对子view 的 要求规范 和 自己可用空间,得出子view 具体尺寸要求

    next:

    noodview(父View) 根节点在自己的onMeasure 中 根据xml定义的对子view 的要求,和自己可用空间,得出对子view 的具体尺寸要求

    子view在自己的onMeasure 根据noodView 的要求以及特性计算出自己的期望尺寸

    如果是viewGroup,还会调用每个子View的measure 进行测量 计算(父View一般会和子View之间宽度相同 或者相加叠加)

    如果自定义子view 宽高 和 父View有冲突,则父View会修正子View大小,例如ConstraintLayout 和 LinearLayout 表现出很大差异

    父View在子View计算出期望尺寸时后,得出子View的实际尺寸和位置

    子View在self的layout中,将父view传来的实际尺寸和位置进行保存

     

    1. public void layout(int l, int t, int r, int b) {
    2. if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
    3. onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
    4. mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
    5. }
    6. int oldL = mLeft;
    7. int oldT = mTop;
    8. int oldB = mBottom;
    9. int oldR = mRight;
    10. boolean changed = isLayoutModeOptical(mParent) ?
    11. setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
    12. if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
    13. onLayout(changed, l, t, r, b);
    14. if (shouldDrawRoundScrollbar()) {
    15. if(mRoundScrollbarRenderer == null) {
    16. mRoundScrollbarRenderer = new RoundScrollbarRenderer(this);
    17. }
    18. } else {
    19. mRoundScrollbarRenderer = null;
    20. }
    21. mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
    22. ListenerInfo li = mListenerInfo;
    23. if (li != null && li.mOnLayoutChangeListeners != null) {
    24. ArrayList<OnLayoutChangeListener> listenersCopy =
    25. (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
    26. int numListeners = listenersCopy.size();
    27. for (int i = 0; i < numListeners; ++i) {
    28. listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
    29. }
    30. }
    31. }
    32. final boolean wasLayoutValid = isLayoutValid();
    33. mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
    34. mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
    35. if (!wasLayoutValid && isFocused()) {
    36. mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
    37. if (canTakeFocus()) {
    38. // We have a robust focus, so parents should no longer be wanting focus.
    39. clearParentsWantFocus();
    40. } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) {
    41. // This is a weird case. Most-likely the user, rather than ViewRootImpl, called
    42. // layout. In this case, there's no guarantee that parent layouts will be evaluated
    43. // and thus the safest action is to clear focus here.
    44. clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
    45. clearParentsWantFocus();
    46. } else if (!hasParentWantsFocus()) {
    47. // original requestFocus was likely on this view directly, so just clear focus
    48. clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
    49. }
    50. // otherwise, we let parents handle re-assigning focus during their layout passes.
    51. } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) {
    52. mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
    53. View focused = findFocus();
    54. if (focused != null) {
    55. // Try to restore focus as close as possible to our starting focus.
    56. if (!restoreDefaultFocus() && !hasParentWantsFocus()) {
    57. // Give up and clear focus once we've reached the top-most parent which wants
    58. // focus.
    59. focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
    60. }
    61. }
    62. }
    63. if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) {
    64. mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
    65. notifyEnterOrExitForAutoFillIfNeeded(true);
    66. }
    67. notifyAppearedOrDisappearedForContentCaptureIfNeeded(true);
    68. }

     

    1. protected boolean setFrame(int left, int top, int right, int bottom) {
    2. boolean changed = false;
    3. if (DBG) {
    4. Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + ","
    5. + right + "," + bottom + ")");
    6. }
    7. if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
    8. changed = true;
    9. // Remember our drawn bit
    10. int drawn = mPrivateFlags & PFLAG_DRAWN;
    11. int oldWidth = mRight - mLeft;
    12. int oldHeight = mBottom - mTop;
    13. int newWidth = right - left;
    14. int newHeight = bottom - top;
    15. boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
    16. // Invalidate our old position
    17. invalidate(sizeChanged);
    18. mLeft = left;
    19. mTop = top;
    20. mRight = right;
    21. mBottom = bottom;
    22. mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
    23. mPrivateFlags |= PFLAG_HAS_BOUNDS;
    24. if (sizeChanged) {
    25. sizeChange(newWidth, newHeight, oldWidth, oldHeight);
    26. }
    27. if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) {
    28. // If we are visible, force the DRAWN bit to on so that
    29. // this invalidate will go through (at least to our parent).
    30. // This is because someone may have invalidated this view
    31. // before this call to setFrame came in, thereby clearing
    32. // the DRAWN bit.
    33. mPrivateFlags |= PFLAG_DRAWN;
    34. invalidate(sizeChanged);
    35. // parent display list may need to be recreated based on a change in the bounds
    36. // of any child
    37. invalidateParentCaches();
    38. }
    39. // Reset drawn bit to original value (invalidate turns it off)
    40. mPrivateFlags |= drawn;
    41. mBackgroundSizeChanged = true;
    42. mDefaultFocusHighlightSizeChanged = true;
    43. if (mForegroundInfo != null) {
    44. mForegroundInfo.mBoundsChanged = true;
    45. }
    46. notifySubtreeAccessibilityStateChangedIfNeeded();
    47. }
    48. return changed;
    49. }

     在setFrame时 , left,top,right,bottom 在layout的时候就已经保存下来了,重写layout 可以改变 这些参数

     如果是ViewGroup,在onLayout中调用每个子View 的layout,并把子view的位置传给子view

  • 相关阅读:
    一台机器下,多个Java版本的粗放与精细管理
    MES系统作业调度
    Java中HashSet类简介说明
    新进场的獴哥健康、至真健康们,讲不出互联网医疗的新故事
    牛客小白月赛55 A-E 回顾
    Selenium IDE的安装以及使用
    【Python】json 格式转换 ① ( json 模块使用 | 列表转 json | json 转列表 | 字典转 json | json 转字典 )
    vue3学习(十二)--- 自定义指令
    选择最适合你的图像分类模型
    【Ubuntu】SMBus Host controller not enabled(虚拟机进入不了图形界面)
  • 原文地址:https://blog.csdn.net/qq_29769851/article/details/133501474