在Android中声明可设置的属性

Ted*_*opp 77 xml android styleable declare-styleable

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

<!-- The most prominent text color.  -->
<attr name="textColorPrimary" format="reference|color" />
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

这两个似乎都声明了一组指定样式的允许值.

所以我有两个问题:

  1. 可以采用一组enum值之一的样式属性与可以采用一组值的样式属性之间的区别是什么flag
  2. 有谁知道任何更好的文档如何declare-styleable工作(除逆向工程Android源代码)?

Ale*_*dam 69

这里有一个问题:用一些信息定义定制的attrs,但不多.

这篇文章.它有关于标志和枚举的良好信息:

自定义XML属性标志

标志是特殊属性类型,因为它们只允许非常小的值子集,即在属性标记下定义的值.标志由"name"属性和"value"属性指定.名称在该属性类型中必须是唯一的,但值不必是.这就是在Android平台发展过程中我们将"fill_parent"和"match_parent"映射到相同行为的原因.他们的价值是相同的.

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

value属性必须是整数.十六进制或标准数字表示的选择取决于您.Android代码中有一些地方使用了这两个地方,Android编译器很乐意接受.

自定义XML属性枚举

枚举以与具有一个规定的标志几乎相同的方式使用,它们可以与整数互换使用.在引擎盖下,枚举和整数映射到相同的数据类型,即整数.当使用整数出现在属性定义中时,枚举用于防止总是坏的"魔术数字".这就是为什么你可以使用带有维度,整数或命名字符串"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>
Run Code Online (Sandbox Code Playgroud)

以这种方式使用Enums时的一个规定是使用自定义View的开发人员可以有目的地将值"-1"放入布局参数中.这将触发"scroll_to_top"的特殊情况逻辑.如果选择Enum值很差,这种意外(或预期)行为可能会迅速将您的库转移到"遗留代码"堆.


正如我所看到的,您可以在实际中添加到属性的真实值受限于您可以从中获得的值.请查看此处AttributeSet类引用以获取更多提示.

你可以获得:

  • 布尔(getAttributeBooleanValue),
  • 浮子(getAttributeFloatValue),
  • ints(getAttributeIntValue),
  • 整数(as getAttributeUnsignedIntValue),
  • 和字符串(getAttributeValue)

  • 链接我的博客的任何人都有+1.我真的试图解析每个标签的用途.它可能不完整,也许应该随着时间的推移而更新,但如果有人有任何东西需要添加,我会全力以赴. (3认同)

Rad*_*ing 65

@Aleadam的回答非常有帮助,但是它忽略了enum和之间的一个主要区别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>
Run Code Online (Sandbox Code Playgroud)

res/layout/mylayout.xml我们现在能做

<com.example.MyWidget
    myenum="two"
    myflags="one|two"
    ... />
Run Code Online (Sandbox Code Playgroud)

因此,枚举选择其中一个可能的值,而标志可以组合.数值应该反映这种差异,通常你会希望序列去0,1,2,3,...枚举(用作数组索引,比如说)和标志去,1,2,4,8,...这样它们可以独立添加或删除,使用按位OR |来组合标志.

我们可以使用不是2的幂的值明确定义"元标志",从而为常见组合引入一种简写.例如,如果我们在myflags声明中包含了这一点

<flag name="three" value="3" />
Run Code Online (Sandbox Code Playgroud)

然后我们可以写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 -->
Run Code Online (Sandbox Code Playgroud)

这将允许我立即取消设置或设置所有标志.

更巧妙的是,可能是另一个标志暗示了一个标志.因此,在我们的示例中,假设eight设置的标志应强制设置four标志(如果尚未设置).然后我们可以重新定义eight以预先包括four旗帜,

<flag name="eight" value="12" /> <!-- 12 == 8|4 -->
Run Code Online (Sandbox Code Playgroud)

最后,如果要声明库项目中的属性但想要将它们应用于另一个项目的布局(依赖于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>
Run Code Online (Sandbox Code Playgroud)