如何在Android布局中按值而不是名称设置枚举属性?

我有一个自定义视图,其中包含另一个自定义视图。等级制度:

MyOuterView
->MyInnerView

MyInnerView具有枚举属性,如下所示:

<attr name="myAttr" format="enum">
    <enum name="foo" value="0"/>
    <enum name="bar" value="1"/>
</attr>

因此,我可以在 XML 中实例化该组件,如下所示:MyOuterView

<com.example.MyInnerView
....
app:myAttr="foo"/>

这当然有效。为自定义本身提供了一个参数。基于这个参数,我想设置 .MyOuterViewMyInnerView

希望的行为是,我可以像这样使用数据绑定:

<com.example.MyInnerView
....
app:myAttr="@{data.getMyAttr()}"/>

其中看起来像:getMyAttr()

public int getMyAttr() {
    return myAttr; // returns 0 or 1
}

结果是编译问题。

/ 数据绑定错误 ****msg:在 com.example.MyInnerView 上找不到参数类型为 int 的属性“app:myAttr”的 setter

所以显然我不能按值设置枚举,只能按名称设置枚举。除了以编程方式创建之外,还有什么想法吗?请注意,我无法更改。MyInnerViewMyInnerView


答案 1

我无法按值设置枚举,但只能按名称设置枚举

这并不完全正确。即使按名称,您也无法使用DataBinding设置值,问题是xml中定义的属性的值被传递给via构造函数。A 可以同时具有属性和二传符,但事实并非如此。例如,是否为 a 设置了一个值,然后将该值设置为 该值,然后从 构造函数中检索该值。如果你使用DataBinding,被调用,但这是两个完全不同的东西,功能是相同的,但它们在代码中不相关。ViewViewandroid:textTextViewcom.android.internal.R.styleable.TextView_textAttributeSetsetText()

鉴于您无法修改并且没有可以调用的 setter,您唯一的选择就是通过构造函数传递它。数据绑定根本不可行,即使使用 BinderAdapter,您也无法在 中设置值,因为 此时已经实例化了。MyInnerViewmyAttrAttributeSetView

备选案文1 - 主题

定义新属性

<attr name="MyInnerViewAttrValue" format="integer" />

然后使用样式解析此属性,例如,您可以

<style name="AppTheme.Foo">
    <item name="MyInnerViewAttrValue">0</item>
</style>

<style name="AppTheme.Bar">
    <item name="MyInnerViewAttrValue">1</item>
</style>

在布局 xml 中设置它

<com.example.MyInnerView
    ...
    app:myAttr="?attr/MyInnerViewAttrValue" />

然后在实例化视图之前调用。setTheme(int)Activity

选项 2 - 自定义绑定适配器

如果你想设置你的值DataBinding(因为你有一个设置器,或者因为你想用反射来破解),那么你需要创建一个自定义的BindingAdapter,例如MyInnerView

@BindingAdapter("myAttrValue")
public static void setMyAttr(MyInnerView myInnerView, int value) {
    switch (value) {
        case 0:
            myInnerView.foo();
            break;
        default:
            myInnerView.bar();
    }
}

然后在布局 xml 中

<com.example.lelloman.dummy.MyInnerView
    ...
    myAttrValue="@{model.attr}" />

并从您的视图模型中提供价值int

public class MyInnerViewModel {

    public int getAttr() {
        return 1234;
    }
}

答案 2

不幸的是,只有当有 setter 并且此 setter 映射到属性名称或可以通过其名称解析时,才能使用属性名称。在你的例子中,如果这个属性只在View的构造函数中使用,并且视图没有任何公共方法来改变这个 - 你仍然有一些可能的解决方案: - 扩展视图并实现逻辑来自定义视图,就像这个属性一样(如果可能的话) - 使BinditionAdapter并使用Refreprem(如果可能)。- 通过复制粘贴和修复创建自己的视图)app:myAttr="@{...}"