@android, ?attr/ 和 ?android 的区别

前言:安卓开发中我们时常会需要引用一些特殊的资源,比如设置一些可点击组件的波纹效果时,我们会用到:android:foreground="?attr/selectableItemBackground",但是这些引用方式之间有哪些区别呢?

获取资源

首先来复习一下安卓中获取资源的几种方式。

@[<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 文件:

appcompat-v7 包下的 colorAccent 属性

关于资源引用的方式,具体请参考官方文档:Accessing your app resources

01 @android: 引用安卓内建的系统资源

除了引用自己应用中的资源外,我们还可以通过指定引用时的包名为 android 来获取安卓平台下的一些系统资源,举个例子:

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

我们知道当新建一个项目的时候,必须在 gradle 中设置 compileSdkVersion 来指定编译我们应用的 SDK 版本,这也决定了我们能调用哪个 level 的 API,同时也表明了哪个 level 的系统资源可供我们使用,比如如果指定的 compileSdkVersion 是 27,那么我们调用的就是 Android 8.1 下的系统资源。

@android:drawable/ic_menu_delete

02 ?attr/: 引用应用内的属性资源

通过这种方式可以让我们间接地使用应用内的某些资源。我们知道当我们自定义View的时候,一般会需要自定义一些属性资源,通常我们会在 values/ 文件夹下建一个 attrs 文件,在这里保存一些我们自己的 style 属性,其实这些属性就可以通过 ?attr/ 这种方式来引用了。比如我在 styles 里定义了一个属性:

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

定义完之后,我就可以直接在 layout 中通过引用的方式去使用这个属性了:

android:background="?attr/colorReallyGreen"

当然,要想让该属性起作用还需要在 Theme 下指定值:

在当前 Theme 下为自定义属性赋值

另外,由于在 layout 中,可以自动识别出当前所需的是属性资源,所以可以省略 attr/ 而直接使用 ?colorReallyGreen 就可以了。

03 ?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 有关。

结语

总结下,获取资源有两种方式,一种是通过直接引用(使用 @),一种是通过 style 属性(使用 ?,除了自定义属性外,引用的资源类型和当前使用的主题有关)。另外系统中内置了不少资源,学会合理利用它们可以帮助我们节约不少时间,建议大家花点精力自己探索下。


参考:

  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