在Android中声明样式属性
有关于declare-styleable
标签的珍贵的小文档,我们可以通过它来声明组件的自定义样式。 我确实find了attr
标签的format
属性的有效值列表 。 虽然这是很好的,但它并没有解释如何使用其中的一些值。 浏览attr.xml (标准属性的Android源代码),我发现你可以做如下的事情:
<!-- The most prominent text color. --> <attr name="textColorPrimary" format="reference|color" />
format
属性显然可以设置为值的组合。 format
属性可能帮助parsing器解释实际的样式值。 然后我在attr.xml中发现了这个:
<!-- Default text typeface. --> <attr name="typeface"> <enum name="normal" value="0" /> <enum name="sans" value="1" /> <enum name="serif" value="2" /> <enum name="monospace" value="3" /> </attr> <!-- Default text typeface style. --> <attr name="textStyle"> <flag name="normal" value="0" /> <flag name="bold" value="1" /> <flag name="italic" value="2" /> </attr>
这两个似乎都为指定的样式声明了一组允许的值。
所以我有两个问题:
- 样式属性可以采用一组
enum
值之一和可以采用一组flag
值的区别是什么? - 有没有人知道更好的文档如何
declare-styleable
工程(除了逆向工程的Android源代码)?
这里有这个问题:用一些信息定义自定义attrs ,但不是很多。
而这个职位 。 它有关于国旗和枚举的很好的信息:
自定义XML属性标志
标志是特殊的属性types,因为它们只允许一小部分值,即在属性标签下定义的那些属性。 标志由“name”属性和“value”属性指定。 名称必须在该属性types中是唯一的,但值不一定是。 这就是在Android平台进化过程中,我们有“fill_parent”和“match_parent”都映射到相同的行为。 他们的价值是相同的。
name属性映射到布局XML中的值位置中使用的名称,不需要命名空间前缀。 因此,对于上面的“tilingMode”,我select了“center”作为属性值。 我可以很容易地select“拉伸”或“重复”,但没有别的。 甚至不能代替实际的价值。
值属性必须是整数。 hex或标准数字表示的select取决于您。 Android代码中有几个地方使用了这两个地方,Android编译器也乐于接受。
自定义XML属性枚举
枚举的使用几乎与一条规定的标志相同,它们可以与整数交替使用。 枚举和整数映射到相同的数据types,即整数。 当用整数出现在属性定义中时,枚举用来防止总是不好的“幻数”。 这就是为什么你可以有一个“android:layout_width”的维度,整数或命名string“fill_parent”。
为了把它放到上下文中,我们假设我创build了一个名为“layout_scroll_height”的自定义属性,它接受一个整数或者一个string“scroll_to_top”。为此我添加一个“整数”格式属性,然后在枚举中加上:
<attr name="layout_scroll_height" format="integer"> <enum name="scroll_to_top" value="-1"/> </attr>
以这种方式使用枚举时的一个规定是,使用您的自定义视图的开发人员可以有意地将值“-1”放入布局参数中。 这将触发“scroll_to_top”的特殊情况逻辑。如果Enum值select不当,这种意外(或预期)的行为可能会很快将您的库归入“遗留代码”堆。
正如我所看到的,实际上可以将属性添加到属性中的真实值受限于您可以从中获得的值。 在这里查看AttributeSet
类的参考以获取更多提示。
您可以获得:
- 布尔值(
getAttributeBooleanValue
), - 浮动(
getAttributeFloatValue
), - ints(
getAttributeIntValue
), - 整数(如
getAttributeUnsignedIntValue
), - 和string(
getAttributeValue
)
@Aleadam的回答是非常有用的,但是imho忽略了enum
和flag
之间的一个主要区别。 前者是为我们select一个,只有一个值,当我们为一些View分配相应的属性。 后者的值可以合并,但是,使用按位或运算符。
例如,在res/values/attr.xml
<!-- declare myenum attribute --> <attr name="myenum"> <enum name="zero" value="0" /> <enum name="one" value="1" /> <enum name="two" value="2" /> <enum name="three" value="3" /> </attr> <!-- declare myflags attribute --> <attr name="myflags"> <flag name="one" value="1" /> <flag name="two" value="2" /> <flag name="four" value="4" /> <flag name="eight" value="8" /> </attr> <!-- declare our custom widget to be styleable by these attributes --> <declare-styleable name="com.example.MyWidget"> <attr name="myenum" /> <attr name="myflags" /> </declare-styleable>
在res/layout/mylayout.xml
我们现在可以做
<com.example.MyWidget myenum="two" myflags="one|two" ... />
所以枚举select其中一个可能的值,而标志可以合并。 数值应该反映这种差异,通常你会想要序列为0,1,2,3,...
为枚举(用作数组索引,比如说)和标志去1,2,4,8,...
所以他们可以被独立地添加或删除,使用按位或|
结合旗帜。
我们可以明确定义“元标志”的值不是2的幂,从而引入一种常用组合的简写。 例如,如果我们把这个包括在我们的myflags
声明中
<flag name="three" value="3" />
那么我们可以用myflags="three"
来代替myflags="one|two"
,与3 == 1|2
完全相同的结果。
我个人喜欢总是包括
<flag name="none" value="0" /> <!-- or "normal, "regular", and so on --> <flag name="all" value="15" /> <!-- 15 == 1|2|4|8 -->
这将允许我一次解除或设置所有的标志。
更为巧妙的是,一个国旗可能是另一个国家的暗示。 所以,在我们的例子中,假设设置的eight
标志应该强制设置four
标志(如果还没有的话)。 然后,我们可以重新定义eight
预先包含four
标志,
<flag name="eight" value="12" /> <!-- 12 == 8|4 -->
最后,如果您在库项目中声明属性,但想要将其应用于另一个项目的布局(取决于lib),则需要使用必须绑定在XML根元素中的名称空间前缀。 例如,
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:auto="http://schemas.android.com/apk/res-auto" ... > <com.example.MyWidget auto:myenum="two" auto:myflags="one|two" ... /> </RelativeLayout>