在Android中声明可样式化的属性


81

关于declare-styleable标签的宝贵文档很少,我们可以通过这些标签声明组件的自定义样式。我确实找到了标签属性的有效值列表。尽管这很好,但并没有说明如何使用其中一些值。浏览attr.xml(标准属性的Android源)时,我发现您可以执行以下操作:formatattr

<!-- The most prominent text color.  -->
<attr name="textColorPrimary" format="reference|color" />

format属性显然可以设置为值的组合。大概该format属性可以帮助解析器解释实际的样式值。然后我在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>

这两个似乎都为指示的样式声明了一组允许的值。

所以我有两个问题:

  1. 可以采用一组enum值之一的样式属性和可以采用一组值的样式属性有什么区别flag
  2. 有谁知道更好的工作方式文档declare-styleable(除了对Android源代码进行反向工程之外)?

Answers:


72

这里有一个问题:用一些信息定义自定义属性,但不多。

还有这个帖子。它具有有关标志和枚举的良好信息:

自定义XML属性标志

标志是特殊的属性类型,因为它们仅允许值的一小部分,即那些在属性标签下定义的值。标志由“名称”属性和“值”属性指定。名称在该属性类型中必须是唯一的,但值不必是唯一的。这就是在Android平台发展过程中,我们将“ fill_parent”和“ match_parent”都映射到相同行为的原因。他们的价值观是相同的。

name属性映射到布局XML的值位置中使用的名称,并且不需要名称空间前缀。因此,对于上面的“ tilingMode”,我选择“ center”作为属性值。我可以很容易地选择“拉伸”或“重复”,但没有别的选择。甚至不允许替换实际值。

value属性必须是整数。十六进制或标准数字表示形式的选择取决于您。Android代码中有几个地方都可以使用这两个地方,Android编译器很乐意接受其中任何一个。

自定义XML属性枚举

枚举的使用方式几乎与带有标志的标记完全相同,它们可以与整数互换使用。在幕后,Enums和Integer映射到相同的数据类型,即Integer。当出现在带有整数的属性定义中时,枚举可防止总是不好的“魔术数字”。这就是为什么您可以使用尺寸,整数或命名字符串“ fill_parent”的“ android:layout_width”的原因。

为了说明这一点,我们假设创建一个名为“ layout_scroll_height”的自定义属性,该属性可以接受整数或字符串“ scroll_to_top”。为此,我将添加一个“整数”格式属性,然后使用枚举:

<attr name="layout_scroll_height" format="integer">  
    <enum name="scroll_to_top" value="-1"/> 
</attr>

以这种方式使用枚举时的一项规定是,使用自定义View的开发人员可以有目的地将值“ -1”放入布局参数中。这将触发“ scroll_to_top”的特殊情况逻辑。如果Enum值选择不当,这种意外(或预期)的行为可能会使您的库迅速脱离“遗留代码”堆。


如我所见,您可以实际添加到属性中的实际值受到从该属性中获取的内容的限制。在此处查看AttributeSet类参考以获取更多提示。

您可以获得:

  • 布尔值(getAttributeBooleanValue),
  • 浮点(getAttributeFloatValue),
  • 整数(getAttributeIntValue),
  • 整数(以表示getAttributeUnsignedIntValue),
  • 和字符串(getAttributeValue

感谢那些链接。静态类型博客特别好。它与“真实文档”足够接近,因此我将其标记为已解决。
泰德·霍普

的确,@ Ted的帖子信息很棒。无论如何,除非您正在编写可重用视图的库或扩展框架,否则我不会担心这些枚举。布尔值,浮点数,整数和字符串可以让您走出常规自定义视图的距离。那当然是,如果问题不仅仅在于满足一个非常健康的好奇心:)
Aleadam 2011年

@Aleadam-这个问题是由一个真实的应用程序引起的。我一直在使用自定义属性,需要添加一个新属性。事实证明,新属性的正确格式是枚举,但是在阅读您提供的链接之前,我找不到任何有关使用enum和的区别的信息flag
特德·霍普

@Ted很高兴它很有用。该博客中还有其他一些有趣的帖子,尽管我只是浏览了一下,但我还没有时间阅读它们。
2011年

3
+1链接我的博客的人。我真的试图解析这些标签中每个标签的用途。它可能并不完整,也许应该随着时间的流逝而更新,但是如果有人要添加任何内容,我将不知所措。
麦币

70

@Aleadam的回答非常有帮助,但是恕我直言,它忽略了enum和之间的主要区别flag。前者旨在让我们选择一个,而当我们为某个视图分配相应的属性时,只能选择一个值。后者的值可以使用按位或运算符组合。

一个例子,在 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"
    ... />

因此,枚举选择其可能的值之一,同时可以组合标志。数值应该反映出这种差异,通常,您希望序列0,1,2,3,...使用枚举(例如,用作数组索引)和标记,1,2,4,8,...以便可以使用按位OR|组合标记来独立地添加或删除它们。

我们可以使用非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>

好点。我想对于熟悉编程语言枚举的人来说,标志和枚举之间的区别是第二天性。(我什至没有意识到Aleadam的答案中没有提到您要表达的观点。)这绝对是有用的附加信息。+1
泰德·霍普

该答案明确指出了在定义自定义属性时如何区分枚举与标志。它显然可以帮助我使用标志:) +1
ptitvinou
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.