Android 属性(attr)引用

前言

经常我们在布局文件中能看到以这样的方式指定某些属性:

            <!-- textAppearance使用系统样式 -->
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"/>

            <!-- textAppearance使用系统属性 -->
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"/>

其中第一个TextView的textAppearance指定为了系统默认定义的Medium样式,这比较好理解。就相当于系统预先定义了一些常用的样式,然后我们使用了这些默认样式。

但是第二种使用方式就比较奇怪了。引用系统定义的属性作为textAppearance?属性不应该是定义来被指定值的吗,怎么还能用来给其他属性赋值?而且这个属性的值又是从哪儿来的呢?

在最开始学习Android时我始终没能理解这里面的逻辑!

其实没那么复杂

直到有一天,我发现我们使用的默认theme其实并不像我们看到的那么简单!

    <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
        <!-- Customize your theme here. -->

        <item name="android:colorPrimary">@color/colorPrimary</item>
        <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="android:colorAccent">@color/colorAccent</item>

    </style>

在AppTheme的祖父“Theme.Material”中定义了非常多的属性值。其中就包括了我们在上面TextView中引用的属性textAppearanceMedium:

<!-- SDK/platforms/android-25/data/res/values/themes_material.xml -->

    <style name="Theme.Material">
        ...
        <item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
        <item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
        <item name="textAppearanceMedium">@style/TextAppearance.Material.Medium</item>
        ...
    </style>

至此恍然大悟!原来引用的属性的值是来自于当前所使用的Theme中的值

这个结论我们可以通过在AppTheme中指定textAppearanceMedium为另一个我们自定义的style,然后看引用该属性的TextView样式是否是我们新引入的style来验证。

为何难以理解

在了解了我们引用的属性是从Theme中取值后,其实又觉得这理解起来很自然。其实属性就相当于一个左值变量,可以被赋值(在theme中),也可以将这个变量作为值赋值给其他变量(属性),而如第一个例子引用的系统样式(style)其实就相当于使用系统定义的常量!
那当时为什么又觉得难以理解呢,我想最主要的因素还是之前我不知道属性的值从何而来!

复盘当时的想法应该是:

首先,对于引用系统style,我们可以直接跳转到那个style看到里面具体定义了什么。发现其结构和我们自己定义的style也差不多,于是这很好理解。
接着,用惯性思维想去查看我们引用的属性(attr)是什么,结果只能跳转到属性定义的地方,没有我们需要的如style般定义很多子元素的信息。因此发现我根本不知道这个属性是个什么东西!

在代码中引用属性

我们可以在xml中用?[android:]attr/xxxx的方式引用属性,也可以在代码中提取这些属性的值,使用如下方法:

        TypedValue tv = new TypedValue();
        //从这里可以明显看到是从theme中提取属性值的!
        getTheme().resolveAttribute(android.R.attr.textAppearance, tv, true);
        int resId = tv.resourceId;

        TextView textView = (TextView) findViewById(R.id.textView);
        textView.setTextAppearance(this, resId);
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页