22

问题

Q1:有没有人设法让自定义字符串/枚举属性在 xml 选择器中工作?我通过遵循 [1] 得到了一个布尔属性,但不是字符串属性。

编辑:感谢您的回答。目前 android 仅支持布尔选择器。有关原因,请参阅已接受的答案。

我打算实现一个有点复杂的自定义按钮,其外观取决于两个变量。其他将是一个布尔属性(真或假)和另一个类属性(具有许多不同的可能值)。我的计划是使用布尔和字符串(或者可能是枚举?)属性。我希望我可以使用布尔和字符串属性在 xml 选择器中定义 UI。

Q2:为什么在 [1] onCreateDrawableState() 中,布尔属性只有在它们为真时才会合并?

这是我测试的,布尔属性有效,字符串无效

注意:这只是一个测试应用程序,用于确定 xml 选择器中是否可以使用字符串/枚举属性。我知道我可以在没有自定义属性的情况下设置按钮的 textcolor。

在我的演示应用程序中,我使用布尔属性将按钮背景设置为暗/亮,并使用字符串属性设置文本颜色,{“red”、“green”、“blue”} 之一。属性定义在/res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCustomButton">
        <attr name="make_dark_background" format="boolean" />
        <attr name="str_attr" format="string" />
    </declare-styleable>
</resources>

以下是我想要实现的选择器:

@drawable/custom_button_background(有效)

<?xml version="1.0" encoding="utf-8"?>
<selector 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.example.customstringattribute">

    <item app:make_dark_background="true" android:drawable="@color/dark" />
    <item android:drawable="@color/bright" />

</selector>

@color/custom_button_text_color(不起作用)

<selector 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.example.customstringattribute">

    <item app:str_attr="red" android:color="@color/red" />
    <item app:str_attr="green" android:color="@color/green" />
    <item app:str_attr="blue" android:color="@color/blue" />

    <item android:color="@color/grey" />

</selector>

这是自定义按钮背景如何连接到布尔选择器,文本颜色如何连接到字符串选择器。

<com.example.customstringattribute.MyCustomButton
    ...
    android:background="@drawable/custom_button_background"
    android:textColor="@color/custom_button_text_color"
    ...
/>

以下是在 init() 方法中加载属性的方式:

private void init(AttributeSet attrs) {

    TypedArray a = getContext().obtainStyledAttributes(attrs,
            R.styleable.MyCustomButton);

        final int N = a.getIndexCount();
        for (int i = 0; i < N; ++i)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
                case R.styleable.MyCustomButton_str_attr:
                    mStrAttr = a.getString(attr);
                    break;
                case R.styleable.MyCustomButton_make_dark_background:
                    mMakeDarkBg  = a.getBoolean(attr, false);
                    break;
            }
        }
        a.recycle();
}

我有属性的 int[] 数组

private static final int[] MAKE_DARK_BG_SET = { R.attr.make_dark_background };
private static final int[] STR_ATTR_ID = { R.attr.str_attr };

并且那些 int[] 数组被合并到可绘制状态

@Override
protected int[] onCreateDrawableState(int extraSpace) {
    Log.i(TAG, "onCreateDrawableState()");
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
    if(mMakeDarkBg){
        mergeDrawableStates(drawableState, MAKE_DARK_BG_SET);
    }
    mergeDrawableStates(drawableState, STR_ATTR_ID);
    return drawableState;
}

我的属性设置器方法中也有 refreshDrawableState() :

public void setMakeDarkBg(boolean makeDarkBg) {
    if(mMakeDarkBg != makeDarkBg){
        mMakeDarkBg = makeDarkBg;
        refreshDrawableState();
    }
}

public void setStrAttr(String str) {
    if(mStrAttr != str){
        mStrAttr = str;
        refreshDrawableState();
    }
}

[1] :如何添加自定义按钮状态

4

3 回答 3

14

Q1:

打开StateListDrawable.java的源码,可以在inflate读取drawable xml选择器的方法中看到这段代码: https ://android.googlesource.com/platform/frameworks/base/+/refs/heads /master/graphics/java/android/graphics/drawable/StateListDrawable.java

        ...

        for (i = 0; i < numAttrs; i++) {
            final int stateResId = attrs.getAttributeNameResource(i);
            if (stateResId == 0) break;
            if (stateResId == com.android.internal.R.attr.drawable) {
                drawableRes = attrs.getAttributeResourceValue(i, 0);
            } else {
                states[j++] = attrs.getAttributeBooleanValue(i, false)
                        ? stateResId
                        : -stateResId;
            }
        }
        ...

attrs是每个<item>元素的属性<selector>

在这个 for 循环中,它获取android:drawable、各种android:state_xxxx和自定义app:xxxx属性。除了属性之外的所有android:drawable属性似乎都被解释为布尔值:attrs.getAttributeBooleanValue(....)被调用。

我认为这是基于源代码的答案:

您只能将自定义布尔属性添加到您的 xml,而不是任何其他类型(包括枚举)。

Q2:

我不确定为什么只有当它被明确设置为 true 时才会合并状态。我怀疑代码应该看起来像这样:

private static final int[] MAKE_DARK_BG_SET     = {  R.attr.make_dark_background };
private static final int[] NOT_MAKE_DARK_BG_SET = { -R.attr.make_dark_background };
....
....
@Override
protected int[] onCreateDrawableState(int extraSpace) {
    Log.i(TAG, "onCreateDrawableState()");
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
    mergeDrawableStates(drawableState, mMakeDarkBg? MAKE_DARK_BG_SET : NOT_MAKE_DARK_BG_SET);
    //mergeDrawableStates(drawableState, STR_ATTR_ID);
    return drawableState;
}
于 2013-03-05T15:24:08.540 回答
1

Q1:

我自己没有尝试过,但是:

你试过把你@color/custom_button_text_color.xml的放在drawable文件夹里吗?(可以肯定的是,Android 中到处都有文件夹魔法,我不确定这个。)

Q2:

状态集有两个用例。一种是以编程方式显式声明有状态可绘制对象的选择器。在这种情况下,对于选择器,如果未设置属性,您需要能够告诉 Android使用此可绘制对象。为了表达这一点,您可以在.int[]

虽然在选择器标准的上下文中几乎没有提到这一点,但对于可绘制状态本身(也就是可绘制状态的表示)从未提及它。因此,如果集合中不包含否定状态 ID,则绝对是安全的;提供的 Android 实现也不包括它们。

于 2013-03-05T11:30:38.967 回答
0

抱歉,您无法在 xml 中创建自定义可绘制对象: https ://groups.google.com/d/msg/android-developers/glpdi0AdMzI/LpW4HGMB3VIJ

于 2013-02-26T23:00:40.553 回答