个人总结:把attr当做变量的声明,使用的时候需要再不同的Theme中定义,也就是赋值。最后使用的时候使用?attr/变量名,引用相关具体值。
摘自:Android中 @和?区别以及?attr/**与@style/**等的区别:
https://blog.csdn.net/xx326664162/article/details/64125654?depth_1-utm_source
@和?的区别
style="?android:attr/progressBarStyleHorizontal"
style="@android:style/Widget.ProgressBar.Horizontal"
- 1
- 2
在设置style的时候既可以使用@也可以使用?,他们有什么区别呢??
- 使用@表示使用固定的style,而不会跟随Theme改变,这style可以在对应的style.xml中找到。
- 使用?表示从Theme中查找引用的资源名,这个google叫预定义样式,用在多主题时的场景,属性值会随着主题而改变。(?需要和attr配合使用)
例如上面的progressBarStyleHorizontal:
查看\platforms\android23\data\res\values\themes.xml文件,可以看到在不同的theme中,progressBarStyleHorizontal引用的style是不同的。看下面的示例:
在Theme中:
<item name="progressBarStyleHorizontal">@style/Widget.ProgressBar.Horizontal</item>
- 1
在Theme.Holo中为
<item name="progressBarStyleHorizontal">@style/Widget.Holo.ProgressBar.Horizontal</item>
- 1
style和attr使用区别
style
<!--使用自定义的style-->
@style/Widget.AppCompat.ProgressBar.Horizontal
<!--使用系统自带的style-->
@android:style/Widget.ProgressBar.Horizontal
- 1
- 2
- 3
- 4
attr
<!--使用自定义的 ,下面两种方式等效-->
"?attr/属性"
"?属性"
<!--使用系统自带的 ,下面两种方式等效-->
"?android:属性"
"?android:attr/属性"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
另外:
当引用系统自带的style和attr时
"@android:style/主题"和"@style/android:主题"等同
"?android:attr/属性"和"?attr/android:属性"等同
- 1
- 2
- 3
自定义随主题改变的属性
个人总结:把attr当做变量的声明,使用的时候需要再不同的Theme中定义,也就是赋值。最后使用的时候使用?attr/变量名,引用相关具体值。
1、 如果是自定义控件,请在style.xml中或attrs.xml中声明属性:(声明后,才可以在xml文件中该控件中使用该属性)
<declare-styleable name="SunnyAttr">
<attr name="sunnyTextColor" format="reference"/>
<attr name="sunnyBgColor" format="reference"/>
<attr name="sunnyTextColorWhite" format="color"/>
<attr name="sunnyTextColorRed" format="reference"/>
<attr name="textColor" format="reference"></attr>
</declare-styleable>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
如代码第五行所示,必须指明format为reference。这样自定义控件的属性就可以在xml使用,如果不明白,查看这里
2、 在Theme中使用自定义的属性,可以在多个主题中定义不同的属性值(在Theme中赋值,但是要在AndroidManifest.xml中使用该Theme才能生效,否则会报错。最后获取的值就是从这儿获取的。具体的值是引用的下面3的)
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="sunnyTextColorRed">@color/sunnyTextColorRed</item>
</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3、 在对应的属性color,drawable等里面加入相应的资源(被引用的属性资源。)
<color name="sunnyTextColorRed">#FFFF0000</color>
- 1
4、这样就可以在xml中使用自定义控件的自定义属性,这个属性会随着主题而改变:(引用2处)
见下面第五行代码
<com.smartbracelet.sunny.sunnydemo3.SunnyTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="设置界面"
app:sunnyTextColor="?attr/sunnyTextColorRed"
/>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
https://blog.csdn.net/s13383754499/article/details/102568854
1,@android: 引用安卓内建的系统资源
除了引用自己应用中的资源外,我们还可以通过指定引用时的包名为 android
来获取安卓平台下的一些系统资源,举个例子:
android:background=“@android:drawable/ic_menu_delete”
我们知道当新建一个项目的时候,必须在 gradle 中设置 compileSdkVersion
来指定编译我们应用的 SDK 版本,这也决定了我们能调用哪个 level 的 API,同时也表明了哪个 level 的系统资源可供我们使用,比如如果指定的 compileSdkVersion
是 27,那么我们调用的就是 Android 8.1 下的系统资源。
2,?attr/: 引用应用内的属性资源
通过这种方式可以让我们间接地使用应用内的某些资源。我们知道当我们自定义View的时候,一般会需要自定义一些属性资源,通常我们会在 values/
文件夹下建一个 attrs
文件,在这里保存一些我们自己的 style 属性,其实这些属性就可以通过 ?attr/
这种方式来引用了。比如我在 styles
里定义了一个属性:
<attr name="colorReallyGreen" format="color"/>
定义完之后,我就可以直接在 layout
中通过引用的方式去使用这个属性了:
android:background="?attr/colorReallyGreen"
当然,要想让该属性起作用还需要在 Theme 下指定值:
在当前 Theme 下为自定义属性赋值
另外,由于在 layout
中,可以自动识别出当前所需的是属性资源,所以可以省略 attr/
而直接使用 ?colorReallyGreen
就可以了。
3,?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 有关。