6

我试图android从我的代码中获取命名空间的几个样式属性。在这里我附上相关的摘录。AttributeSet attrs是传递给任何 custom 的参数TextView

private static final int[] ATTRS = new int[] { android.R.attr.textSize,
   android.R.attr.text, android.R.attr.textColor,
   android.R.attr.gravity };

private void processAndroidAttributes(final Context context,
   final AttributeSet attrs) {
   final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
   try {

       final String text = a.getString(1);
       myTextView.setText(text);
       final float textSize = a.getDimensionPixelSize(0, DEFAULT_TEXT_SIZE);
       myTextView.setTextSize(textSize);
}

我的问题是我想阅读 4 个属性,在int[] ATTRS. 如您所见,我已将textSize其作为该数组的第一个元素。原因很简单——如果我将它交换到数组中的第二位,则它的值不会被正确读取(而是加载了提供的默认值)。另一方面,文本正确加载到ATTRS我放置它的数组中的任何位置。我不敢尝试 和 的位置偏好gravitytextColor但是通过这种排列它们不起作用。

有人可以解释为什么获取属性的可用行为吗?

4

5 回答 5

12

这似乎是 API 中的一个错误。我对 4 个属性进行了测试:gravitytext和. 这是我使用的代码:textSizetextColor

private void processAndroidAttributes(final Context context, final AttributeSet attrs) {
    ATTRS = new Integer[] {
               android.R.attr.textSize, android.R.attr.text,
               android.R.attr.textColor, android.R.attr.gravity };
    Arrays.sort(ATTRS);
    do {
        printPermutation(ATTRS);
        tryApplyingStyles(context, attrs, ATTRS);
        ATTRS = nextPermutation(ATTRS);
    } while ((ATTRS = nextPermutation(ATTRS)) != null);
}

该方法processAndroidAttributes尝试应用所有列出的属性并检查是否应用了它们或使用了默认值。对于每次迭代,我都会打印数组ATTRS内容以及是使用了实际值(用 标记1)还是使用了默认值(用 标记0)。这是我运行上述代码后得到的结果(每次迭代都会打印几行):

[16842901,16842904,16842927,16843087]
1111
[16842901,16842904,16843087,16842927]
1110
[16842901,16842927,16842904,16843087]
1101
[16842901,16842927,16843087,16842904]
1101
[16842901,16843087,16842904,16842927]
1100
[16842901,16843087,16842927,16842904]
1100
[16842904,16842901,16842927,16843087]
1011
[16842904,16842901,16843087,16842927]
1010
[16842904,16842927,16842901,16843087]
1011
[16842904,16842927,16843087,16842901]
1011
[16842904,16843087,16842901,16842927]
1010
[16842904,16843087,16842927,16842901]
1010
[16842927,16842901,16842904,16843087]
1001
[16842927,16842901,16843087,16842904]
1001
[16842927,16842904,16842901,16843087]
1001
[16842927,16842904,16843087,16842901]
1001
[16842927,16843087,16842901,16842904]
1001
[16842927,16843087,16842904,16842901]
1001
[16843087,16842901,16842904,16842927]
1000
[16843087,16842901,16842927,16842904]
1000
[16843087,16842904,16842901,16842927]
1000
[16843087,16842904,16842927,16842901]
1000
[16843087,16842927,16842901,16842904]
1000
[16843087,16842927,16842904,16842901]
1000

正如您所看到的,这几乎就像期望对数组进行排序一样,只有几个异常值。我认为这是 Android API 中的一个错误,因为它的文档obtainStyledAttributes没有指定期望属性 ID 的任何排序。

于 2013-09-30T10:58:24.787 回答
1

我在尝试获取 3 种不同类型的 4 个属性时遇到了同样的问题。总是只有一种类型的属性传递给数组,这总是第一个。例如,如果您声明 {int, String, Color} 之类的属性:

private static final int[] ATTRS = new int[] { android.R.attr.textSize,
   android.R.attr.text, android.R.attr.textColor }

方法obtainStyledAttributes将只传递给您TypedArray的 int 属性,其余的将为空。

如果您将顺序更改为 {String, Color, int}:

private static final int[] ATTRS = new int[] {android.R.attr.text, android.R.attr.textColor, android.R.attr.textSize }

您将仅获得 String 属性TypedArray,其余为空。

看起来它TypedArray只能包含一个类型,因此您需要声明更多的 TypeArrays - 每种类型的属性一个。

像这样:

private static final int[] stringAttrs = new int[] {android.R.attr.text};
private static final int[] intAttrs = new int[] {android.R.attr.textSize};
private static final int[] colorAttrs = new int[] {android.R.attr.textColor, android.R.attr.background};

    private void processAndroidAttributes(final Context context,
       final AttributeSet attrs) {
       final TypedArray stringA = context.obtainStyledAttributes(attrs, stringAttrs);
       final TypedArray intA = context.obtainStyledAttributes(attrs, intAttrs);
       final TypedArray colorA = context.obtainStyledAttributes(attrs, colorAttrs);

       myTextView.setText(stringA.getString(0));
       myTextView.setTextSize(intA.getDimensionPixelSize(0, DEFAULT_TEXT_SIZE));
       myTextView.setTextColor(colorA.getColor(0, Color.WHITE));
       myTextView.setBackgroundColor(colorA.getColor(1, Color.WHITE));

       stringA.recycle();
       intA.recycle();
       colorA.recycle();

    }
于 2013-11-07T14:16:44.760 回答
1

我很惊讶有人和我有同样的结论。我决定为obtainStyledAttributes 使用一个唯一的项目数组,这样我就不必担心顺序了。

http://androidxref.com/2.2.3/xref/frameworks/base/core/jni/android_util_AssetManager.cpp#911 我没有仔细查看这个来源,但我猜android只按升序迭代 AttributeSet 一次效率。

于 2013-11-08T01:45:09.917 回答
1

我确认了所讨论的问题,并添加了一个简单的解决方案以供将来参考。有关详细信息,请参阅其他答案。

注意2点:

  1. int[] attrs 数组值名称按字母顺序排序
  2. 我们调用 gainStyledAttributes(AttributeSet, int[], int int)

    public static int[] getCommonStyledAttributes() {
      return new int[] {
        R.attr.bottom, //0
        R.attr.height, //1
        R.attr.layout, //2
        R.attr.left, //3
        R.attr.paddings, //4
        R.attr.right, //5
        R.attr.top, //6
        R.attr.width //7
      };
    }
    
    TypedArray a = context.getTheme().obtainStyledAttributes(paramAttributeSet, getCommonStyledAttributes(), 0, 0);
        this.mWidth = a.getInt(7, 0);
        this.mHeight = a.getInt(1, 0);
        this.left = a.getInt(3, 0);
        this.top = a.getInt(6, 0);
        this.right = a.getInt(5, 0);
        this.bottom = a.getInt(0, 0);
        this.type = a.getInt(2, 0);
        a.recycle();
    
于 2014-03-25T08:23:48.637 回答
0

我认为这可能是因为 int[] 通常来自 xml,并且会在“编译”时进行排序,例如检查这里的用例:

如何:为自定义小部件定义主题(样式)项

其中数组来自 R.styleable.CustomImageButton 而不是手工制作。

我可以理解它们使用并期望排序数组,因为在编译时优化 xml 资源需要做很多工作,以便在运行时有效地使用它们。

于 2014-01-20T10:05:03.693 回答