目錄

一、基礎知識
在學習View的作業原理之前,需要先學習一些基本的概念,
2.1 ViewRoot
Q1: ViewRoot是什么?
- 對應
ViewRootImpl類,- 連接
WindowManagerService和DecorView的紐帶,
Q2:ViewRoot在View繪制中有什么作用?
- View的三大流程(測量(
measure),布局(layout),繪制(draw))均通過ViewRoot來完成,
注意:ViewRoot并不屬于View樹的一份子,從原始碼實作上來看,它既非View的子類,也非View的父類,但是,它實作了ViewParent介面,這讓它可以作為View的名義上的父視圖,
View的繪制流程從ViewRoot的performTraversals開始,如圖,
onMeasure方法會對所有子元素進行measure程序,在measure方法中又會呼叫onMeasure方法,如此反復最終完成整個View樹的遍歷,layout,draw方法同理,

2.2 DecorView
Q1:DecorView是什么?
包括兩部分,標題欄和內容欄,如圖,
DecorView是FrameLayout的子類,它可以被認為是Android視圖樹的根節點視圖,setContentView所布置的檔案是被加入內容欄的,
Q: DecorView在View繪制中有什么作用?
View層的事件都需先經過
DecorView,再傳遞給View,分發的程序在View體系詳解有講到,

2.3 ViewGroup.LayoutParams
此部分參考自:自定義View Measure程序 - 最易懂的自定義View原理系列(2)
Q1:怎么理解ViewGroup.LayoutParams?
ViewGroup的子類(RelativeLayout、LinearLayout)有其對應的ViewGroup.LayoutParams子類如:
RelativeLayout的ViewGroup.LayoutParams子類 =RelativeLayoutParams
Q2: 這個類有什么作用?
指定視圖
View的高度(height)和 寬度(width)等布局引數,
Q3:怎么使用?
| 引數 | 解釋 |
|---|---|
| 具體值 | dp / px |
| fill_parent | 強制性使子視圖的大小擴展至與父視圖大小相等(不含 padding ) |
| match_parent | 與fill_parent相同,用于Android 2.3 & 之后版本 |
| wrap_content | 自適應大小,強制性地使視圖擴展以便顯示其全部內容(含 padding ) |
2.4 MeasureSpec
定義:測量規格類,
組成:測量規格
(MeasureSpec)= 測量模式(mode)(高2位) + 測量大小(size)(低30位),作用:通過寬測量值
widthMeasureSpec和高測量值heightMeasureSpec決定View的大小,
Q1:為什么說是很大程度決定了View的尺寸規格?
答:View的尺寸規格還受父容器影響,因為父容器影響View的MeasureSpec的創建程序,
Q2:MeasureSpec有幾種模式?
測量模式
(Mode)的型別有3種:UNSPECIFIED、EXACTLY 和
AT_MOST,

2.4.1 MeasureSpec值的計算
View: 取決于View的布局引數(
LayoutParams)和父容器的MeasureSpec值,頂級View: 取決于自身布局引數 和視窗尺寸,



二、View的作業流程
以下流程圖的方法為原始碼中的方法,感興趣的讀者可以自行查看原始碼,強推Carson_Ho博客,內有詳細解讀,
2.1 measure
作用:測量View的寬/高,
注意:某些情況需要多次
measure才能確定View的寬高,此時測驗的結果不準確,建議在layout程序中onLayout()獲取最終寬/高,
measure測量有兩種情況:
- 單一
View ViewGroup

2.1.1 View

說明:
Measure程序中,主要目的就是為了測量出View的寬/高,在measure()入口方法中呼叫了onMeasure(),而在onMeasure方法中,呼叫了getDefaultSize()得出測量后View的寬/高,再呼叫setMeasureDimension()存盤測量后的寬高,測量程序到此結束,結果是存盤了一個測量后的寬高,
Q1:measure流程最后使用的是getDefaultSize()得出的寬/高,那么這個寬/高是什么?
-
AT_MOST和EXACTLY:
getDefaultSize()回傳的大小是measureSpec中的specSize,這個specSize就是最終的測量結果, -
UNSPECIFIED:
-
有背景
寬/高為
android:minWidth屬性所指定的值,若無指定,則為0, -
無背景
View的寬/高度為android:minWidth/android:minHeight屬性所指定的值和mBackground.getMinimumWidth()/mBackground.getMinimumHeight()中的最大值,

-
2.1.2 ViewGroup
ViewGroup除了完成自己的measure程序之外,還會遍歷所有子View的measure方法,
ViewGroup是一個抽象類,沒有重寫View的onMeasure方法(自定義View時需要自己實作),提供了一個
measureChildren方法,

說明:在
ViewGroup的measure程序中,先在入口measure()內呼叫onMeasure(),與View中的onMeasure不同,ViewGroup中沒有實作這個方法,因為不同的ViewGroup子類(LinearLayout、RelativeLayout/ 自定義ViewGroup子類等)具備不同的布局特性,這導致他們子View的測量方法各有不同,故需自己重寫,在這個方法中包含了三個方法
measureChildren()系統方法,遍歷子View 并且呼叫
measureChild()進行下一步測量,
measureCarson()需要自己重寫,合并所有子View的尺寸大小,最終得到
ViewGroup父視圖的測量值,
setMeasureDimension()與單一View一樣,存盤測量后的資料,
2.2 layout
作用:確定View的位置,

2.2.1 View

說明:
由于單一View是沒有子View的,故o
nLayout()是一個空實作,由于在
layout()中已經對自身View進行了位置計算,所以單一View的layout程序在layout()后就已完成了,
2.2.2 ViewGroup

說明:
Viewgroup在onLayout方法中遍歷了子View,呼叫child.layout(),計算每個子View的位置,一開始計算ViewGroup位置時,呼叫的是ViewGroup的layout()和onLayout(),當遍歷子View計算子View位置時,呼叫的是子View的layout()和onLayout(),
2.3 draw
作用:將View繪制到螢屏上面,

2.3.1 View

說明:所有的視圖最終都是呼叫 View 的 draw ()繪制視圖,
2.3.1 ViewGroup

三、自定義View
3.1 自定義View的分類
- 繼承View重寫
onDraw方法- 主要用于實作一些不規則的效果,
- 重寫
onDraw方法,需要支持wrap_content并且需要自己處理padding,
- 繼承
ViewGoup派生特殊的Layout(除了系統布局,重新定義一種新布局)- 實作自定義布局,
- 需要合適的處理
ViewGroup的測量,布局兩個程序,并同時處理子元素的測量和布局程序,
- 繼承特定的
View- 擴展某些已有的View的功能,
- 容易實作,不需要自己支持wrap_content和padding,
- 繼承特定的
ViewGroup- 常見,第二種情況實作的也能用這種方式實作,
- 與第二種的區別就是不用自己處理
ViewGroup的測量和布局,第二種更接近底層,
3.2 自定義View須知
- 讓View支持wrap_content
- 讓View支持padding
- 不要在View中使用Handler
- View內部本身有post系列的方法,可以完全替代Handler的作用,
- View中如果有執行緒或影片,需要及時停止
- 與生命周期同步,不然會造成記憶體泄漏
- 處理滑動沖突
參考自:
- 《Android開發藝術探索》
- 《Android進階之光》
- 自定義View Measure程序 - 最易懂的自定義View原理系列(2)
- 進階之路 | 奇妙的View之旅
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/148657.html
標籤:其他
上一篇:Android反編譯apk修改版本號重新打包簽名詳細教程(超詳細)
下一篇:隨機刷題記錄(就很迷)
