閑談 Android 中的 @ 和 ?符號的引用區別
在 Android 項目開發中,我們經常會用 “@” 或者 “?” 符號去引用系統或者我們應用內添加的資源,這兩種符號的引用有什么區別呢,“?attr/” 與 “?android:attr/” 之間又有怎樣的不同呢?本文我們不妨閑聊一下。
“@” 與 “?” 符號的引用在使用時都有一個規范的格式: “@[+][package:]type:name” , “?[package:][type:]name” 。可以看到,二者均包含引用符號、資源所屬的包、資源類型和資源名稱。
@ 資源引用
“@” 符號用于引用系統和我們在項目中添加的一些固有資源(drawable,string 等),或者定義的 style 樣式。比如:
android:text="@string/app_name"
這里的 app_name 就是我們自己定義在項目文件 values/strings.xml 中的字符串資源。
android:text="@android:string/cancel"
而這里的 cancel 屬于 Android SDK 中的系統字符串資源,所以需要添加 @android: 來指明引用來源。 android: 是 package: 的一個具體實例。
? 屬性引用
“?” 符號用于引用當前主題中定義的一些屬性值。注意,“?” 符號通過屬性名字間接引用當前主題中的對應屬性值,而不是屬性本身。舉個例子:
android:divider="?android:listDivider"
這里的 “?” 符號通過屬性名 android:listDivider 間接獲取當前主題賦予該屬性的值。如同 @android: 一般, ?android: 表示該值源自 Android SDK 系統屬性。由于在當前主題中尋找對應屬性名的值,所以沒有指定屬性類型,其實等同于: ?android:attr/listDivider 。
那如何引用項目中自定義的屬性呢?我們在 attrs.xml 中定義一個屬性,如:
<declare-styleable name="CustomTextView">
<attr name="colorTextCustom" format="reference|color"/>
</declare-styleable>
顯然,此時我們定義的 colorTextCustom 屬性是沒有值的,直接引用沒有任何作用。需要在主題 style 中賦值:
<style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorTextCustom">#FF0000</item>
</style>
<style name="AppTheme" parent="BaseTheme">
<item name="android:textColor">?colorTextCustom</item>
</style>
可以看到,這里在 BaseTheme 中對 colorTextCustom 屬性賦值,并在 AppTheme 中通過 “?colorTextCustom” 引用該屬性值。由于是本地項目中定義的屬性,所以沒有添加 android: 命名空間。其實,這種做法的好處是,AppTheme 所覆蓋的 View 均可通過構造函數獲取當前主題中的 colorTextCustom 屬性值。
R.attr & R.style
Android SDK 中定義有很多屬性和主題可供使用,詳見官方文檔: R.attr & R.style 。使用系統資源的好處就是,滿足不同系統的適配需求,較為靈活。
這里舉幾個常用的:
style=”?android:attr/borderlessButtonStyle”
Android 5.0 默認 Button 的樣式自帶邊框陰影,可以使用這個系統樣式去除該樣式。當然,這是單獨設置時的操作,為了方便全局控制,可以在 styles.xml 中自定義一個樣式,繼承一個無邊框樣式作為 parent:
<style name="CustomBorderlessButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless">
<item name="android:textColor">@android:color/white</item>
...
</style>
android:background=”?android:attr/selectableItemBackground”
可用于設置一些 List Item、Button之類帶點擊效果的背景。該樣式自帶觸摸點擊效果,在 5.0 和更高版本上,更是附有 Ripple 漣漪效果,省去我們自己實現 selector 選擇器的過程。當然我們也可以自己使用 <ripple> 標簽定義一個 drawable 文件實現漣漪效果,只是需要注意版本限制。
android:background=”?android:attr/dividerVertical”
實現分割線背景。
還有一些其他有用的系統資源,這里就不一一列舉了…
來自:http://yifeng.studio/2017/03/14/the-difference-between-two-ways-reference-in-android/