天天看點

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念

Android進階知識(十二):View的工作原理之基本概念

  從這一篇章開始,筆者将介紹關于View的工作原理與自定義View的相關内容。在介紹View的工作原理(三大流程)之前,讀者有必要了解一些基本概念。

一、Activity的視圖層結構

  在ActivityThread中,當Activity對象被建立完畢之後,會将DecorView添加到Window中。Window是一個抽象類,其唯一實作類為PhoneWindow,PhoneWindow将一個DecorView設定為整個應用視窗的頂級View。

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念

  DecorView作為視窗界面的頂級View,封裝了一些操作視窗的基本方法,其繼承自FrameLayout(說明DecorView是一個ViewGroup),View層的事件都是先經過DecorView,然後才傳遞給View。值得一提的是,在Activity中通過setContentView設定的布局檔案其實是被添加到id為content的内容欄中。

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念

二、ViewRoot

  ViewRoot對應于ViewRootImpl類,其為連接配接WindowManager和DecorView的紐帶,View的三大流程均是ViewRoot來完成的。在ActivityThread中,當Activity對象被建立完畢之後,會将DecorView添加到Window中,同時會建立ViewRootImpl對象,并将ViewRootImpl對象和DecorView建立關聯(至于這些關聯關系,筆者後續将單獨做一篇介紹)。

  View的繪制流程是從ViewRoot的performTraversals方法開始的,其經過measure、layout和draw三個過程才能最終将一個view繪制出來。performTraversals的工作流程如下所示。

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念

  performTraversals會依次調用performMeasure、performLayout和performDraw三個方法,這三個方法分别完成頂級View的measure、layout和draw這三大流程。其中在performMeasure中會調用measure方法,在measure方法中又會調用onMeasure方法,在onMeasure方法中則會對所有子元素進行measure過程,這就把measure過程傳遞給子元素中。performLayout和performDraw的傳遞流程和performMeasure類似,唯一不同的是,performDraw的傳遞過程是在draw方法中通過dispatchDraw來實作的(具體的三大流程過程見見:Android進階知識(十三):View的工作流程之measure過程與Android進階知識(十四):View的工作流程之Layout過程和Draw過程)。

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念

  Measure過程決定了View測量的寬/高,幾乎所有情況下測量後的寬/高等同于View最終的寬高。Layout過程決定了View四個頂點的坐标和實際的View的寬/高,可通過getWith和getHeight擷取最終寬/高。Draw過程決定了View的顯示,隻有draw方法完成以後View的内容才能呈現。

三、LayoutParams

  LayoutParams是布局參數類,其指定了視圖View的高度和寬度等布局參數,可以通過以下參數指定。

參數 解釋
具體值 dp/px
fill_parent 強制性使子視圖的大小擴充至與父視圖大小相等(不含padding)
match_parent 與fill_parent相同,用于Android 2.3之後版本
wrap_content 自适應大小,強制性地使視圖擴充以便顯示其全部内容(含padding)

四、了解MeasureSpec

  為了能夠了解View的measure過程,對于參與View測量過程的MeasureSpec必須要有所了解,MeasureSpec在很大程度上決定了一個View的尺寸規格。

  一個View的MeasureSpec一旦确定之後,onMeasure中就可以确定View的測量寬/高。

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念
  1. MeasureSpec

  MeasureSpec代表一個32位int值,高2位代表SpecMode(測量模式),低30位代表SpecSize(某種測量模式下的規格大小)。

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念

  MeasureSpec通過将SpecMode和SpecSize打包成一個int值來避免過多的對象記憶體配置設定。其中SpecMode 有三類,每一類都表示特殊的含義,如下所示。

模式 具體描述 應用場景
UNSPECIFIED 父容器不對View有任何限制(即View可取任意大小) 系統内部,表示一種測量的狀态
EXACTLY 父容器已經檢測出View所需的精确大小,View的最終大小就是SpecSize所指定的值 對應于LayoutParams中的match_parent和具體數值這兩種模式
AT_MOST 父容器指定一個可用大小即SpecSize,View的大小不能大于這個值 對應于LayoutParams中的wrap_content
  1. MeasureSpec和LayoutParams的對應關系

  上面提到了,MeasureSpec很大程度上決定了View的尺寸規格,這裡之是以說很大程度,原因在于View的尺寸還和LayoutParams有關。

  對于DecorView,其MeasureSpec由視窗的尺寸和其自身的LayoutParams來共同決定。

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念

  根據ViewRootImpl的源碼,DecorView的MeasureSpec的産生過程比較明确,根據它的LayoutParams中的寬/高來劃分如下表所示。

LayoutParams DecorView的MeasureSpec
MATCH_PARENT EXACTLY + 視窗大小
WRAP_CONTENT AT_MOST + 大小不定,但不能超過視窗大小
固定大小(比如100dp) EXACTLY + LayoutParams中指定大小

  而對于普通View,其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams來共同決定。

Android進階知識(十二):View的工作原理之基本概念Android進階知識(十二):View的工作原理之基本概念

  根據ViewGroup的相關源碼,可以得到普通View的MeasureSpec的建立規則,如下表所示,其中表中的paresentSize是指父容器中目前可使用大小(除去padding和margin)。

parentSpecMode \ childLayoutParams EXACTLY AT_MOST UNSPECIFIED
dp/px EXACTLY + childSize EXACTLY + childSize EXACTLY + childSize
match_parent EXACTLY + parentSize AT_MOST + parentSize UNSPECIFIED + 0
wrap_content AT_MOST + parentSize AT_MOST + parentSize UNSPECIFIED + 0

參考資料:《Android開發藝術探索》

     自定義View Measure過程 - 最易懂的自定義View原理系列(2)

繼續閱讀