@android, ?attr/ 和 ?android 的區(qū)別

前言:安卓開發(fā)中我們時(shí)常會(huì)需要引用一些特殊的資源,比如設(shè)置一些可點(diǎn)擊組件的波紋效果時(shí),我們會(huì)用到:android:foreground="?attr/selectableItemBackground",但是這些引用方式之間有哪些區(qū)別呢?

獲取資源

首先來復(fù)習(xí)一下安卓中獲取資源的幾種方式。

@[<package_name>:]<resource_type>/<resource_name>

這種方式是最為常見的,直接獲取對(duì)應(yīng)的包下的資源,一般在相同的包下,可以省略包名,比如為 TextView 設(shè)置文字時(shí),就可以通過這樣的方式來獲取我們應(yīng)用內(nèi)定義的 string 資源:

android:text="@string/hello"

另一種獲取資源的方式是通過引用 style 屬性。

android:textColor="?colorAccent"

通過這種方式,我們可以獲取到當(dāng)前應(yīng)用主題下的 style 屬性值,這些屬性值一般可以在屬性文件夾 values 下找到。這里由于當(dāng)前使用的是 Theme.AppCompat 下的主題,這是 com.android.support:appcompat-v7 下的 Theme,所以 colorAccent 會(huì)指向該庫下的 values 文件:

appcompat-v7 包下的 colorAccent 屬性

關(guān)于資源引用的方式,具體請(qǐng)參考官方文檔:Accessing your app resources

01 @android: 引用安卓內(nèi)建的系統(tǒng)資源

除了引用自己應(yīng)用中的資源外,我們還可以通過指定引用時(shí)的包名為 android 來獲取安卓平臺(tái)下的一些系統(tǒng)資源,舉個(gè)例子:

android:background=“@android:drawable/ic_menu_delete”

我們知道當(dāng)新建一個(gè)項(xiàng)目的時(shí)候,必須在 gradle 中設(shè)置 compileSdkVersion 來指定編譯我們應(yīng)用的 SDK 版本,這也決定了我們能調(diào)用哪個(gè) level 的 API,同時(shí)也表明了哪個(gè) level 的系統(tǒng)資源可供我們使用,比如如果指定的 compileSdkVersion 是 27,那么我們調(diào)用的就是 Android 8.1 下的系統(tǒng)資源。

@android:drawable/ic_menu_delete

02 ?attr/: 引用應(yīng)用內(nèi)的屬性資源

通過這種方式可以讓我們間接地使用應(yīng)用內(nèi)的某些資源。我們知道當(dāng)我們自定義View的時(shí)候,一般會(huì)需要自定義一些屬性資源,通常我們會(huì)在 values/ 文件夾下建一個(gè) attrs 文件,在這里保存一些我們自己的 style 屬性,其實(shí)這些屬性就可以通過 ?attr/ 這種方式來引用了。比如我在 styles 里定義了一個(gè)屬性:

<attr name="colorReallyGreen" format="color"/>

定義完之后,我就可以直接在 layout 中通過引用的方式去使用這個(gè)屬性了:

android:background="?attr/colorReallyGreen"

當(dāng)然,要想讓該屬性起作用還需要在 Theme 下指定值:

在當(dāng)前 Theme 下為自定義屬性賦值

另外,由于在 layout 中,可以自動(dòng)識(shí)別出當(dāng)前所需的是屬性資源,所以可以省略 attr/ 而直接使用 ?colorReallyGreen 就可以了。

03 ?android: 引用系統(tǒng)內(nèi)建的屬性資源

了解了前兩種資源引用的方式后,?android 這種引用資源的方式也就不難理解了。與 ?attr/ 類似,通過這種方式可以直接訪問到安卓內(nèi)建的屬性資源,只不過是省略了 attr/ 而已。比如給 TextView 引用一個(gè)系統(tǒng)內(nèi)的 style buttonStyleSmall

<TextView
    style="?android:buttonStyleSmall"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="You Are Beautiful" />

然后 TextView 就變成了這樣:

引用了安卓內(nèi)建屬性作為 style 的 TextView

當(dāng)然如果你嘗試去掉 android 包名之后,發(fā)現(xiàn)該屬性還是可以起作用,說明應(yīng)用內(nèi)也是可以引用這個(gè)資源的。那么這是不是意味著絕大部分屬性資源都不需要加 android 包名呢?其實(shí)我覺得是這樣的,因?yàn)榧恿税笃鋵?shí)限制反而會(huì)更多,比如有些內(nèi)建屬性資源是針對(duì)某個(gè) API level 以上的 Android 平臺(tái)才可以使用的,當(dāng)然這也與你當(dāng)前使用的 Theme 有關(guān)。

結(jié)語

總結(jié)下,獲取資源有兩種方式,一種是通過直接引用(使用 @),一種是通過 style 屬性(使用 ?,除了自定義屬性外,引用的資源類型和當(dāng)前使用的主題有關(guān))。另外系統(tǒng)中內(nèi)置了不少資源,學(xué)會(huì)合理利用它們可以幫助我們節(jié)約不少時(shí)間,建議大家花點(diǎn)精力自己探索下。


參考:

  1. What‘s the difference between “?android:attr/” and “?attr/” in an android layout xml file?
  2. Difference between “?attr/” and “?android:attr/” in android
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容