在Android中声明可设置的属性

时间:2011-05-16 16:28:05

标签: android xml styleable declare-styleable

关于declare-styleable标签的珍贵文档很少,我们可以通过它来声明组件的自定义样式。我确实找到format标记的attr属性的有效值this list。虽然这很好,但它没有解释如何使用其中的一些值。浏览attr.xml(标准属性的Android源代码),我发现您可以执行以下操作:

<!-- 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源代码)?

2 个答案:

答案 0 :(得分:69)

这里有一个问题:Defining custom attrs 一些信息,但不多。

这是post。它有关于标志和枚举的良好信息:

  

自定义XML属性标志

     

标志是特殊的属性类型   他们只被允许了   值的一小部分,即那些   在下面定义的   属性标签。标志由。指定   “名称”属性和“值”   属性。这些名字是必需的   在该属性类型中是唯一的   但价值观不一定是。这是   进化过程中的原因   我们拥有的Android平台   “fill_parent”和“match_parent”都是   映射到相同的行为。其   价值观相同。

     

name属性映射到名称   用在价值所在的地方   布局XML并不需要   命名空间前缀因此,对于   上面的“tilingMode”我选择了“中心”作为   属性值。我本可以有   就像容易选择“拉伸”或   “重复”但没有别的。不   甚至代替实际价值   本来可以的。

     

value属性必须是   整数。十六进制或。十六进制的选择   标准数字表示已启动   给你。里面有几个地方   两者都使用的Android代码   并且Android编译器很乐意   接受。

     

自定义XML属性枚举

     

枚举使用几乎完全相同   作为一个条款的标志的方式,   它们可以互换使用   整数。在引擎盖Enums和   整数映射到相同的数据   type,即Integer。什么时候   出现在属性定义中   使用整数,枚举可以防止   “神奇数字”总是很糟糕。   这就是为什么你可以拥有一个   “android:layout_width”与a   维,整数或命名字符串   “FILL_PARENT。”

     

要把它放到上下文中,让我们来吧   假设我创建了一个自定义   属性叫   “layout_scroll_height”接受   整数或字符串   “scroll_to_top。”为此,我要添加一个   “整数”格式属性并遵循   与enum:

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

使用Enums时的一个规定   以这种方式是开发人员   使用您的自定义View可以   故意将值“-1”放入   布局参数。这个会   触发特殊情况逻辑   “scroll_to_top。”这样的意外(或   预期)行为可能很快   将你的图书馆归入“遗产”   代码“如果Enum值是桩的话   选择不好。

     

正如我所看到的,您可以在实际中为属性添加的真实值受限于您可以从中获得的内容。查看AttributeSet课程参考here以获取更多提示。

您可以获得:

  • 布尔(getAttributeBooleanValue),
  • 浮动(getAttributeFloatValue),
  • ints(getAttributeIntValue),
  • 整数(作为getAttributeUnsignedIntValue),
  • 和字符串(getAttributeValue

答案 1 :(得分:63)

@Aleadam的答案非常有帮助,但是它忽略了enumflag之间的一个主要区别。前者用于我们选择一个,当我们为某个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,...因此它们可以是独立的添加或删除,使用按位OR |组合标记。

我们可以明确定义&#34;元标记&#34;值不是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>