闲谈 Android 中的 @ 和 ?符号的引用区别
04041035
8年前
<p>在 Android 项目开发中,我们经常会用 “@” 或者 “?” 符号去引用系统或者我们应用内添加的资源,这两种符号的引用有什么区别呢,“?attr/” 与 “?android:attr/” 之间又有怎样的不同呢?本文我们不妨闲聊一下。</p> <p>“@” 与 “?” 符号的引用在使用时都有一个规范的格式: <strong>“@[+][package:]type:name”</strong> , <strong>“?[package:][type:]name”</strong> 。可以看到,二者均包含引用符号、资源所属的包、资源类型和资源名称。</p> <h2>@ 资源引用</h2> <p>“@” 符号用于引用系统和我们在项目中添加的一些固有资源(drawable,string 等),或者定义的 style 样式。比如:</p> <pre> <code class="language-java">android:text="@string/app_name" </code></pre> <p>这里的 app_name 就是我们自己定义在项目文件 values/strings.xml 中的字符串资源。</p> <pre> <code class="language-java">android:text="@android:string/cancel" </code></pre> <p>而这里的 cancel 属于 Android SDK 中的系统字符串资源,所以需要添加 <strong>@android:</strong> 来指明引用来源。 <strong>android:</strong> 是 <strong>package:</strong> 的一个具体实例。</p> <h2>? 属性引用</h2> <p>“?” 符号用于引用当前主题中定义的一些属性值。注意,“?” 符号通过属性名字间接引用当前主题中的对应属性值,而不是属性本身。举个例子:</p> <pre> <code class="language-java">android:divider="?android:listDivider" </code></pre> <p>这里的 “?” 符号通过属性名 android:listDivider 间接获取当前主题赋予该属性的值。如同 <strong>@android:</strong> 一般, <strong>?android:</strong> 表示该值源自 Android SDK 系统属性。由于在当前主题中寻找对应属性名的值,所以没有指定属性类型,其实等同于: <strong>?android:attr/listDivider</strong> 。</p> <p>那如何引用项目中自定义的属性呢?我们在 attrs.xml 中定义一个属性,如:</p> <pre> <code class="language-java"><declare-styleable name="CustomTextView"> <attr name="colorTextCustom" format="reference|color"/> </declare-styleable> </code></pre> <p>显然,此时我们定义的 colorTextCustom 属性是没有值的,直接引用没有任何作用。需要在主题 style 中赋值:</p> <pre> <code class="language-java"><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> </code></pre> <p>可以看到,这里在 BaseTheme 中对 colorTextCustom 属性赋值,并在 AppTheme 中通过 “?colorTextCustom” 引用该属性值。由于是本地项目中定义的属性,所以没有添加 <strong>android:</strong> 命名空间。其实,这种做法的好处是,AppTheme 所覆盖的 View 均可通过构造函数获取当前主题中的 colorTextCustom 属性值。</p> <h2>R.attr & R.style</h2> <p>Android SDK 中定义有很多属性和主题可供使用,详见官方文档: <a href="/misc/goto?guid=4959741542082883238" rel="nofollow,noindex">R.attr</a> & <a href="/misc/goto?guid=4959741542165572163" rel="nofollow,noindex">R.style</a> 。使用系统资源的好处就是,满足不同系统的适配需求,较为灵活。</p> <p>这里举几个常用的:</p> <p>style=”?android:attr/borderlessButtonStyle”</p> <p>Android 5.0 默认 Button 的样式自带边框阴影,可以使用这个系统样式去除该样式。当然,这是单独设置时的操作,为了方便全局控制,可以在 styles.xml 中自定义一个样式,继承一个无边框样式作为 parent:</p> <pre> <code class="language-java"><style name="CustomBorderlessButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless"> <item name="android:textColor">@android:color/white</item> ... </style> </code></pre> <p>android:background=”?android:attr/selectableItemBackground”</p> <p>可用于设置一些 List Item、Button之类带点击效果的背景。该样式自带触摸点击效果,在 5.0 和更高版本上,更是附有 Ripple 涟漪效果,省去我们自己实现 selector 选择器的过程。当然我们也可以自己使用 <ripple> 标签定义一个 drawable 文件实现涟漪效果,只是需要注意版本限制。</p> <p>android:background=”?android:attr/dividerVertical”</p> <p>实现分割线背景。</p> <p>还有一些其他有用的系统资源,这里就不一一列举了…</p> <p> </p> <p>来自:http://yifeng.studio/2017/03/14/the-difference-between-two-ways-reference-in-android/</p> <p> </p>