android 布局过程

布局流程

开发者意见->父view意见->本身去测量->父view拿到实际尺寸位置,调用layout方法布局

  1. 运行前,开发者在xml文件写入对view的要求xml

  2. 父view在本身的onMeasure中根据开发者在xml中写对子view的要求,和本身的可用空间得出对子view的要求继承

  3. 子view在本身的onMeasure中,根据本身的特性算出本身指望的尺寸递归

    ① 若是是ViewGroup,还会调用每一个子view的measure进行测量开发

  4. 父view在子view计算出指望尺寸后,得出子view的实际尺寸和位置get

  5. 子view在本身的layout方法中,将父view传进来的本身的实际尺寸和位置保存it

    ① 若是是VIewGroup,还会在onLayout里面调用每一个子view的layout把它们的尺寸位置传递给他们io

具体开发中的使用

继承已有的view,简单改写尺寸
  1. 重写onMeasureclass

  2. getMeasuredWidth和getMeasuredSize获取到测量出的尺寸遍历

  3. 计算出最终须要的尺寸

  4. setMeasureDimension(width,height)把结果保存

对自定义view彻底进行自定义尺寸计算
  1. 重写onMeasure

  2. 计算出本身的尺寸

  3. 用resolveSize或则resolveSizeAndState修正结果

    内部实现:

    ① 首先用MeasureSpec.getMode(measureSpec)和MeasureSpec.getSize(MeasureSpec)去出对本身的尺寸限制类型和限制尺寸

    ② 若是measureSpec的mode是EXACTLY,表示父view对子view的尺寸作出了精的限制,直接用measureSpec的size

    ③ 若是measureSpec的mode是AT_MOST,表示父view对子view的尺寸只限制了上限,要具体看状况

    1. size不大于spec限制的size,即是没有超限,选用计算出的size

    2. size大于spec限制的size,超限了,选用spec的size

    3. mode是UNSPECIFIED,表示父view对子view没有任何尺寸限制,直接选用计算的size

  4. 使用setMeasuredDimension(width,height)保存结果

自定义layout:重写onMeasure和onLayout
  1. 重写onMeasure

    ① 遍历每一个子view,用measureChildWidthMargins测量子view

    1. 须要重写generateLayoutParams并返回MarginLayoutParams才能使用measureChildWithMargins方法

    2. 有些子view须要从新测量 当换行时须要

    3. 测量完成后,得出子View的实际位置和尺寸,并暂时保存

      ① measureChildWidthMargins的内部实现

      1. 经过getChildMeasureSpec方法算出子view的widthMeasureSpec和heightMeasureSpec,而后调用child.measure方法让子view自我测量

      2. getChildMeasureSpec方法内部是现实结合开发者设置的LayoutParams中的width和heigth与父view本身的可用空间,得出对子view的限制,并使用MeasureSpec.makeMeasureSpec来求得结果

      ② 测量出全部子view的位置和尺寸后,计算出本身的尺寸,并用setMeasuredDimension保存

  2. 重写onLayout

    遍历每一个子view,调用他们的layout方法来将位置和尺寸传给他们

杂谈

  1. 有些父view会对子view进行纠正,如constraintLayout就会强行纠正你自定view的长和宽

  2. 通常没人重写layout方法

  3. onLayout负责递归对子view进行赋值,和layout方法不同

  4. 测量的过程也能够换一种方法来理解

    ① 若是开发者写了具体值(例如 layout_width="24dp"),就不用再考虑父View 的剩余空间了,直接用 LayoutParams.width / height 来做为子 View的限制 size,而限制 mode 为 EXACTLY,由于冲突致使界面不正确,开发者能够经过修改 xml 文件来解决,因此开发者的意见是第一位

    ② 若是开发者写的是 MATCH_PARENT,即要求填满父控件的可用空间,那么因为本身的可用空间和本身的两个 MeasureSpec 有关,因此须要根据本身的 widthMeasureSpec 或 heightMeasureSpec 中的 mode 来分状况判断:

    1. 若是本身的 spec 中的 mode 是 EXACTLY 或者 AT_MOST,说明本身的尺⼨寸有上限,那么把 spec 中的 size 减去本身的已用宽度或高度,就是本身能够给子 View 的 size;至于 mode,就用 EXACTLY(注意:就算本身的 mode 是 AT_MOST,传给子 View 的也是EXACTLY);
    2. 若是本身的 spec 中的 mode 是 UNSPECIFIED,说明本身的尺⼨寸没有上限,那么让子 View 填满本身的可用空间就无从提及,所以选用退让方案:给子 View 限制的 mode 就设置为 UNSPECIFIED,size 写 0 就好;

    ③ 若是开发者写的是 WRAP_CONTENT,即要求子 View 在不超限制的前提下自我测量,那么一样因为本身的可用空间和本身的两个 MeasureSpec 有关,因此也须要根据本身的 widthMeasureSpec 和 heightMeasureSpec中的 mode 来分状况判断:

    1. 若是本身的 spec 中的 mode 是 EXACTLY 或者 AT_MOST,说明本身的尺寸有上限,那么把 spec 中的 size 减去本身的已用宽度或高度,就是本身能够给⼦子 View 的尺寸上限;至于 mode,就用AT_MOST;
    2. 若是本身的 spec 中的 mode 是 UNSPECIFIED,说明本身的尺⼨寸没有上限,那么也就没必要限制子 View 的上限,所以给子 View 限制的mode 就设置为 UNSPECIFIED,size 写 0 就好。
相关文章
相关标签/搜索