一步步深入瞭解View

Android LayoutInflater原理分析

LayoutInflater得到它的實例的2種基本用法

  1. 第一種:
LayoutInflater layoutInflater = LayoutInflater.from(context);
  1. 第二種:
LayoutInflater layoutInflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

第一種是第二種的簡單寫法。然後就調用它的inflate()方法來加載佈局了。

layoutInflater.inflate(resourceId, root);
inflate(int resource, ViewGroup root, boolean attachToRoot)

上面有2個參數和3個參數的inflate()方法
nflate()方法一般接收兩個參數,第一個參數就是要加載的佈局id,第二個參數是指給該佈局的外部再嵌套一層父佈局,如果不需要就直接傳null。這樣就成功成功創建了一個佈局的實例,之後再將它添加到指定的位置就可以顯示出來了。
那麼第三個參數是什麼呢?結論:
1. 如果root爲null,attachToRoot將失去作用,設置任何值都沒有意義。
2. 如果root不爲null,attachToRoot設爲true,則會給加載的佈局文件的指定一個父佈局,即root。
3. 如果root不爲null,attachToRoot設爲false,則會將佈局文件最外層的所有layout屬性進行設置,當該view被添加到父view當中時,這些layout屬性會自動生效。
4. 在不設置attachToRoot參數的情況下,如果root不爲null,attachToRoot參數默認爲true。

layout_width和layout_height的實際意思

平時我們經常使用layout_width和layout_height來設置View的大小,並且一直都能正常工作,就好像這兩個屬性確實是用於設置View的大小的。而實際上則不然,它們其實是用於設置View在佈局中的大小的,也就是說,首先View必須存在於一個佈局中,之後如果將layout_width設置成match_parent表示讓View的寬度填充滿布局,如果設置成wrap_content表示讓View的寬度剛好可以包含其內容,如果設置成具體的數值則View的寬度會變成相應的數值。這也是爲什麼這兩個屬性叫作layout_width和layout_height,而不是width和height。平時在Activity中指定佈局文件的時候,最外層的那個佈局是可以指定大小的呀,layout_width和layout_height都是有作用的。確實,這主要是因爲,在setContentView()方法中,Android會自動在佈局文件的最外層再嵌套一個FrameLayout,所以layout_width和layout_height屬性纔會有效果。
任何一個Activity中顯示的界面其實主要都由兩部分組成,標題欄和內容佈局。標題欄就是在很多界面頂部顯示的那部分內容,可以在代碼中控制讓它是否顯示。而內容佈局就是一個FrameLayout,這個佈局的id叫作content,我們調用setContentView()方法時所傳入的佈局其實就是放到這個FrameLayout中的,這也是爲什麼這個方法名叫作setContentView(),而不是叫setView()。

以上是根據郭大神Android LayoutInflater原理分析,帶你一步步深入瞭解View(一)的學習的。

Android視圖繪製流程完全解析

  1. onMeasure()
    measure是測量的意思,那麼onMeasure()方法顧名思義就是用於測量視圖的大小的。View系統的繪製流程會從ViewRoot的performTraversals()方法中開始,在其內部調用View的measure()方法。measure()方法接收兩個參數,widthMeasureSpec和heightMeasureSpec,這兩個值分別用於確定視圖的寬度和高度的規格和大小。onMeasure()方法是可以重寫的,也就是說,如果你不想使用系統默認的測量方式,可以按照自己的意願進行定製。
    需要注意的是,在setMeasuredDimension()方法調用之後,我們才能使用getMeasuredWidth()和getMeasuredHeight()來獲取視圖測量出的寬高,以此之前調用這兩個方法得到的值都會是0。

  2. onLayout()
    這個方法是用於給視圖進行佈局的,也就是確定視圖的位置。ViewRoot的performTraversals()方法會在measure結束後繼續執行,並調用View的layout()方法來執行此過程。ViewGroup中的onLayout()方法是一個抽象方法,這就意味着所有ViewGroup的子類都必須重寫這個方法。
    getWidth()方法和getMeasureWidth()方法到底有什麼區別呢?
    首先getMeasureWidth()方法在measure()過程結束後就可以獲取到了,而getWidth()方法要在layout()過程結束後才能獲取到。另外,getMeasureWidth()方法中的值是通過setMeasuredDimension()方法來進行設置的,而getWidth()方法中的值則是通過視圖右邊的座標減去左邊的座標計算出來的。

  3. onDraw()
    這裏才真正地開始對視圖進行繪製。ViewRoot中的代碼會繼續執行並創建出一個Canvas對象,然後調用View的draw()方法來執行具體的繪製工作。draw()方法內部的繪製過程總共可以分爲六步,其中第二步和第五步在一般情況下很少用到。Canvas這個類的用法非常豐富,基本可以把它當成一塊畫布,在上面繪製任意的東西。

根據郭大神的Android視圖繪製流程完全解析,帶你一步步深入瞭解View(二)

Android視圖狀態及重繪流程分析

視圖狀態

  1. enabled
    表示當前視圖是否可用。可以調用setEnable()方法來改變視圖的可用狀態,傳入true表示可用,傳入false表示不可用。它們之間最大的區別在於,不可用的視圖是無法響應onTouch事件的。

  2. focused
    表示當前視圖是否獲得到焦點。通常情況下有兩種方法可以讓視圖獲得焦點,即通過鍵盤的上下左右鍵切換視圖,以及調用requestFocus()方法。而現在的Android手機幾乎都沒有鍵盤了,因此基本上只可以使用requestFocus()這個辦法來讓視圖獲得焦點了。而requestFocus()方法也不能保證一定可以讓視圖獲得焦點,它會有一個布爾值的返回值,如果返回true說明獲得焦點成功,返回false說明獲得焦點失敗。一般只有視圖在focusable和focusable in touch mode同時成立的情況下才能成功獲取焦點,比如說EditText。

  3. window_focused
    表示當前視圖是否處於正在交互的窗口中,這個值由系統自動決定,應用程序不能進行改變。
  4. selected
    表示當前視圖是否處於選中狀態。一個界面當中可以有多個視圖處於選中狀態,調用setSelected()方法能夠改變視圖的選中狀態,傳入true表示選中,傳入false表示未選中。
  5. pressed
    表示當前視圖是否處於按下狀態。可以調用setPressed()方法來對這一狀態進行改變,傳入true表示按下,傳入false表示未按下。通常情況下這個狀態都是由系統自動賦值的,但開發者也可以自己調用這個方法來進行改變。

視圖重繪

調用視圖的setVisibility()、setEnabled()、setSelected()等方法時都會導致視圖重繪,而如果我們想要手動地強制讓視圖進行重繪,可以調用invalidate()方法來實現。
調用視圖的invalidate()方法後確實會走到performTraversals()方法中,然後重新執行繪製流程。
另外需要注意的是,invalidate()方法雖然最終會調用到performTraversals()方法中,但這時measure和layout流程是不會重新執行的,因爲視圖沒有強制重新測量的標誌位,而且大小也沒有發生過變化,所以這時只有draw流程可以得到執行。而如果你希望視圖的繪製流程可以完完整整地重新走一遍,就不能使用invalidate()方法,而應該調用requestLayout()了。

郭大神的Android視圖狀態及重繪流程分析,帶你一步步深入瞭解View(三)

Android自定義View的實現方法

如果說要按類型來劃分的話,自定義View的實現方式大概可以分爲三種,自繪控件、組合控件、以及繼承控件。

  1. 自繪控件
    自繪控件的意思就是,這個View上所展現的內容全部都是我們自己繪製出來的。繪製的代碼是寫在onDraw()方法中的。

  2. 組合控件
    組合控件的意思就是,我們並不需要自己去繪製視圖上顯示的內容,而只是用系統原生的控件就好了,但我們可以將幾個系統原生的控件組合到一起,這樣創建出的控件就被稱爲組合控件。(例如標題欄就是最常見的組合控件)

  3. 繼承控件
    繼承控件的意思就是,我們並不需要自己重頭去實現一個控件,只需要去繼承一個現有的控件,然後在這個控件上增加一些新的功能,就可以形成一個自定義的控件了。這種自定義控件的特點就是不僅能夠按照我們的需求加入相應的功能,還可以保留原生控件的所有功能。

郭大神的Android自定義View的實現方法,帶你一步步深入瞭解View(四)

自定義View欄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章