深入理解Android View的建構函式

2021-09-08 07:36:20 字數 4546 閱讀 7887

原文:a deep dive into android view constructors

我經常看到關於android view構造方法的困惑。為什麼有四個構造方法?每個引數是做什麼的?我需要實現哪個構造方法?

如果你想要乙個直接而實際的建議,這裡有幾個不錯的指導原則:

對於那些仍和我一樣想繼續**的人-讓我們深入下去吧。

構造函式引數最多有四個。簡單總結下:

除了context,其它的引數只是用來通過xml屬性配置view的初始狀態(從布局,style以及theme中)。

讓我們從如何定義xml屬性的開始討論。這裡是乙個xml中最基本的imageview:

android:layout_width

="wrap_content"

android:layout_height

="wrap_content"

android:src

="@drawable/icon"

/>

你有沒有想過這裡的layout_width, layout_height 以及 src是從**來的?它們可不是憑空產生的;實際上是通過把這些屬性明確的宣告為系統需要處理的東西。比如,src就是在這裡定義的:

name

="imageview"

>

name

="src"

format

="reference|color"

/>

每個declare-styleable產生乙個r.styleable.[name],外加每個屬性的r.styleable.[name]_[attribute] 。比如,上面的**產生r.styleable.imageview和r.styleable.imageview_src。

這些資源是什麼東西呢?r.styleable.[name]是所有屬性資源的陣列,系統使用它來查詢屬性值。每個r.styleable.[name]_[attribute]只不過是這個陣列的索引罷了,所以你可以一次性取出所有屬性,然後分別查詢每個的值。

如果你把它想象成乙個cursor,r.styleable.[name]就可以看成是乙個待查詢的column列表,而r.styleable.[name]_[attribute]就是乙個column的索引。

關於declare-styleable的更多資訊,這裡是關於自定義declare-styleable的 官方文件。

上面寫的xml是以乙個attributeset的形式傳遞給view的。

通常你不直接使用attributeset。而是使用theme.obtainstyledattributes()。這是因為原始的屬性通常需要引用和應用樣式。比如,如果你在xml中定義了style=@style/mystyle,這個方法先獲取mystyle,然後把它的屬性混合進去。最終obtainstyledattributes() 返回乙個typedarray,你可以用它來獲取屬性值。

這個過程簡化之後就像這樣:

public

imageview

(context

context

,attributeset

attrs

)

這裡我們向obtainstyledattributes()傳遞了兩個引數。第乙個引數是attributeset attrs,即xml中的屬性,表示從layout檔案中直接為這個view新增的屬性的集合(一種是直接使用android:layout_width="wrap_content"這種直接指定,還有一種是通過style="@style/somestyle"指定。)。第二個引數是r.styleable.imageview陣列,它告訴這個方法我們想取哪個屬性的值,這裡表示要獲取imageview屬性的值。

當獲得了typedarray之後,我們就可以獲取單個屬性了。我們需要使用 r.styleable.imageview_src來正確索引陣列中的屬性。

通常我們可以一次獲取多個屬性。實際上,真實imageview的實現要比上面的複雜多了。

旁註:attributeset並不是obtainstyledattributes() 獲取屬性值的唯一地方。屬性也可以存在於主題中。但是它在view inflate的過程中扮演著不重要的角色,因為主題一般不會設定src這樣的屬性。但是如果你使用obtainstyledattributes() 獲取主題屬性的話它就有作用了(這也是很有用的知識,不過不在本文的討論範圍)。

你可能注意到了obtainstyledattributes()的最後兩個引數我使用的值為0。實際上它們是兩個資源引用-defstyleattr 和 defstyleres。這裡我將關注的是第乙個。

defstyleattr是obtainstyledattributes()最令人困惑的引數。根據官網:

當前主題中包含了為typedarray提供預設值的樣式資源的引用的乙個屬性。

讓我們介紹一下它實際是如何工作的,以textview為例。

首先,他是乙個屬性(這裡是,r.attr.textviewstyle)。這裡是安卓系統定義textviewstyle的地方:

name

="theme"

>

name

="textviewstyle"

format

="reference"

/>

又一次的,我們使用了declare-styleable,但是這次是用來定義存在於theme中的屬性。這裡我們說textviewstyle是乙個reference- 即,它的值只是乙個資源的引用,這裡,它應該是乙個指向style的引用。

接下來,我們必須在當前主題設定textviewstyle。預設的android主題如下:

android:name

=".myactivity"

android:theme

="@style/theme"

/>

現在我們就可以在obtainstyledattributes()裡使用它了:

typedarray

ta =

theme

.obtainstyledattributes

(attrs,r

.styleable

.textview,r

.attr

.textviewstyle,0

);

最終的效果是,任何沒有在attributeset中定義的屬性都將用textviewstyle引用的樣式填充。

除非你在寫核心原始碼,否則你並不需要知道這些實現的細節。它的存在主要是android framework為了讓你可以在主題裡為不同的view定義基礎樣式。

defstyleres就要比defstyleattr簡單多了。它只是乙個style資源(@style/widget.textview)。不需要間接的通過theme。

只有在defstyleattris沒有定義的情況下,才會應用style中的defstyleres(設定為0,或者沒有在主題中設定)。

我們現在有了一些列通過obtainstyledattributes()獲取屬性值的方式。這裡是它們的優先順序,從高到低:

定義在attributeset中的值

定義在attributeset中的style資源(比如:style=@style/blah)

defstyleattr指定的預設樣式。

defstyleresource指定的預設樣式資源(如果沒有defstyleattr)

主題中的值

換句話說,任何直接在xml中設定的屬性都將首先被使用。但是如果你沒有設定,這些屬性也可以從其它地方獲取。

本文不是應該討論view的建構函式的嗎?

總共有四個建構函式,依次增加乙個引數:

view

(context

)view

(context

,attributeset

)view

(context

,attributeset

,defstyleattr

)view

(context

,attributeset

,defstyleattr

,defstyleres

)

注意:最後乙個是在api 21新增的。因此除非你的minsdkversion為21,否則不要使用它。(如果你想使用defstyleres只需自己呼叫obtainstyledattributes()就好了)

它們是串聯的,因此如果你呼叫了乙個,所有的都會被呼叫(通過super)。串聯還意味著你只需重寫你需要的建構函式。一般來說,你只需實現前兩個(乙個用於**,乙個用於xml inflation)。

我一般這樣設定我的自定義view:

someview

(context

context

)someview

(context

context

,attributeset

attrs

)

總之,希望本文不僅幫助你理解了view的構造方法,還幫你了解屬性是如何在view構造期間獲取的!

**:

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...

mysql 索引深入理解 深入理解MySql的索引

為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...