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 就好。
相關文章
相關標籤/搜索