84

关于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 源代码进行逆向工程)?
4

2 回答 2

76

这里有这个问题:Defining custom attrs with some info,但不多。

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

自定义 XML 属性标志

标志是特殊的属性类型,因为它们只允许使用非常小的值子集,即那些在属性标签下定义的值。标志由“名称”属性和“值”属性指定。名称在该属性类型中必须是唯一的,但值不必是唯一的。这就是在 Android 平台的演变过程中,我们将“fill_parent”和“match_parent”都映射到相同行为的原因。它们的值是相同的。

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

value 属性必须是整数。十六进制或标准数字表示的选择取决于您。Android 代码中有几个地方同时使用了两者,Android 编译器也乐于接受。

自定义 XML 属性枚举

枚举的使用方式几乎与带有一个规定的标志相同,它们可以与整数互换使用。在引擎盖下,枚举和整数映射到相同的数据类型,即整数。当出现在带有整数的属性定义中时,枚举用于防止总是不好的“幻数”。这就是为什么您可以使用维度、整数或命名字符串“fill_parent”的“android:layout_width”。</p>

为了将其置于上下文中,假设我创建了一个名为“layout_scroll_height”的自定义属性,它接受整数或字符串“scroll_to_top”。为此,我将添加一个“整数”格式属性,然后使用枚举:

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

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


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

您可以获得:

  • 布尔值 ( getAttributeBooleanValue),
  • 浮动(getAttributeFloatValue),
  • 整数 ( getAttributeIntValue),
  • 整数(如getAttributeUnsignedIntValue),
  • 和字符串 ( getAttributeValue)
于 2011-05-16T17:31:00.090 回答
74

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

一个例子,在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,...以便可以使用按位或|组合标志来独立添加或删除它们。

我们可以用不是 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 -->

最后,如果您在库项目中声明属性但想将它们应用到另一个项目的布局中(依赖于库),则需要使用必须在 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>
于 2014-03-12T19:38:33.050 回答