【问题标题】:Declaring styleable attributes in Android在 Android 中声明可样式化的属性
【发布时间】:2011-08-26 14:19:01
【问题描述】:

关于declare-styleable 标记的宝贵文档很少,我们可以通过它为组件声明自定义样式。我确实为attr 标签的format 属性找到了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 源代码进行逆向工程)?

【问题讨论】:

    标签: android xml styleable declare-styleable


    【解决方案1】:

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

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

    自定义 XML 属性标志

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

    name 属性映射到名称 用在值的地方 布局 XML 并且不需要 命名空间前缀。因此,对于 上面的“tilingMode”我选择了“center”作为 属性值。我本可以有 就像容易选择的“拉伸”或 “重复”,但仅此而已。不是 甚至代入实际值 本来是允许的。

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

    自定义 XML 属性枚举

    枚举以几乎相同的方式使用 方式作为带有一项规定的旗帜, 它们可以与 整数。在引擎盖下枚举和 整数映射到相同的数据 类型,即 Integer。什么时候 出现在属性定义中 使用整数,枚举用于防止 “魔术数字”总是很糟糕。 这就是为什么你可以拥有一个 “android:layout_width” 与 维度、整数或命名字符串 “fill_parent。”

    为了说明这一点,让我们 假设我创建了一个自定义 属性称为 “layout_scroll_height”接受 整数或字符串 “滚动到顶部。”为此,我会添加一个 “整数”格式属性并遵循 与枚举:

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

    使用枚举时的一个规定 以这种方式是开发人员 使用您的自定义视图可以 有目的地将值“-1”放入 布局参数。这个会 触发特殊情况逻辑 “滚动到顶部。”这种意想不到的(或 预期)行为可能很快 将您的图书馆降级为“传统 代码”堆,如果枚举值是 选的不好。


    在我看来,你可以在现实中添加到属性的真实值受到你可以从中获得的东西的限制。查看AttributeSet 类参考here 以获得更多提示。

    您可以获得:

    • 布尔值 (getAttributeBooleanValue),
    • 浮动(getAttributeFloatValue),
    • 整数 (getAttributeIntValue),
    • 整数(如getAttributeUnsignedIntValue),
    • 和字符串 (getAttributeValue)

    【讨论】:

    • 感谢这些链接。静态类型的博客特别好。它与“真实文档”足够接近,我将其标记为已解决。
    • @Ted 确实,那个帖子有很多信息。无论如何,除非您正在编写可重用视图库或扩展框架,否则我不会担心这些枚举。布尔值、浮点数、整数和字符串可以让您远离常规自定义视图。也就是说,当然,如果这个问题不仅仅是为了满足一个非常健康的好奇心:)
    • @Aleadam - 这个问题是由一个真实的应用程序引起的。我一直在使用自定义属性,需要添加一个新属性。事实证明,新属性的正确格式是枚举,但在阅读您提供的链接之前,我找不到任何关于使用 enumflag 之间区别的信息。
    • @Ted 我很高兴它有用。那个博客里还有一些其他的帖子看起来很有趣,虽然我只是浏览了一下,但我还没有时间阅读它们。
    • +1 对于链接我博客的任何人。我真的试图解析每个标签的用途。它可能不完整,也许应该随着时间的推移而更新,但如果有人有什么要补充的,我会全力以赴。
    【解决方案2】:

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

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

    【讨论】:

    • 好点。我想对于熟悉编程语言枚举的人来说,标志和枚举之间的区别将是第二天性。 (我什至没有意识到 Aleadam 的回答中遗漏了您提出的观点。)这绝对是有用的附加信息。 +1
    • 这个答案清楚地指出了如何在定义自定义属性时区分枚举和标志。它显然帮助我使用标志:) +1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2017-08-27
    • 2020-12-30
    相关资源
    最近更新 更多