前言:安卓開發中我們時常會需要引用一些特殊的資源,比如設定一些可點選元件的波紋效果時,我們會用到:android:foreground="?attr/selectableItemBackground",但是這些引用方式之間有哪些差別呢?
1,擷取資源
首先來複習一下安卓中擷取資源的幾種方式。
@[<package_name>:]<resource_type>/<resource_name>
這種方式是最為常見的,直接擷取對應的包下的資源,一般在相同的包下,可以省略包名,比如為 TextView 設定文字時,就可以通過這樣的方式來擷取我們應用内定義的 string 資源
android:text="@string/hello"
另一種擷取資源的方式是通過引用
style
屬性。
android:textColor="?colorAccent"
通過這種方式,我們可以擷取到目前應用主題下的
style
屬性值,這些屬性值一般可以在屬性檔案夾
values
下找到。這裡由于目前使用的是
Theme.AppCompat
下的主題,這是
com.android.support:appcompat-v7
下的 Theme,是以
colorAccent
會指向該庫下的
values
檔案:

關于資源引用的方式,具體請參考官方文檔:Accessing your app resources
2,@android: 引用安卓内建的系統資源
除了引用自己應用中的資源外,我們還可以通過指定引用時的包名為
android
來擷取安卓平台下的一些系統資源,舉個例子:
android:background=“@android:drawable/ic_menu_delete”
我們知道當建立一個項目的時候,必須在 gradle 中設定
compileSdkVersion
來指定編譯我們應用的 SDK 版本,這也決定了我們能調用哪個 level 的 API,同時也表明了哪個 level 的系統資源可供我們使用,比如如果指定的
compileSdkVersion
是 27,那麼我們調用的就是 Android 8.1 下的系統資源。
3,?attr/: 引用應用内的屬性資源
通過這種方式可以讓我們間接地使用應用内的某些資源。我們知道當我們自定義View的時候,一般會需要自定義一些屬性資源,通常我們會在
values/
檔案夾下建一個
attrs
檔案,在這裡儲存一些我們自己的 style 屬性,其實這些屬性就可以通過
?attr/
這種方式來引用了。比如我在
styles
裡定義了一個屬性:
<attr name="colorReallyGreen" format="color"/>
定義完之後,我就可以直接在
layout
中通過引用的方式去使用這個屬性了:
android:background="?attr/colorReallyGreen"
當然,要想讓該屬性起作用還需要在 Theme 下指定值:
在目前 Theme 下為自定義屬性指派
另外,由于在
layout
中,可以自動識别出目前所需的是屬性資源,是以可以省略
attr/
而直接使用
?colorReallyGreen
就可以了。
4,?android: 引用系統内建的屬性資源
了解了前兩種資源引用的方式後,
?android
這種引用資源的方式也就不難了解了。與
?attr/
類似,通過這種方式可以直接通路到安卓内建的屬性資源,隻不過是省略了
attr/
而已。比如給 TextView 引用一個系統内的 style
buttonStyleSmall
:
<TextView
style="?android:buttonStyleSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="You Are Beautiful" />
然後 TextView 就變成了這樣:
引用了安卓内建屬性作為 style 的 TextView
當然如果你嘗試去掉
android
包名之後,發現該屬性還是可以起作用,說明應用内也是可以引用這個資源的。那麼這是不是意味着絕大部分屬性資源都不需要加
android
包名呢?其實我覺得是這樣的,因為加了包名之後其實限制反而會更多,比如有些内建屬性資源是針對某個 API level 以上的 Android 平台才可以使用的,當然這也與你目前使用的 Theme 有關。