如何从Java代码中读取自定义维度属性

39

我通过将几个TextView组合在一起来创建了我的自定义组件。现在我希望能够直接从代码中初始化我的自定义控件,并为每个TextView独立传递文本大小。

我的属性定义:

<resources>
    <declare-styleable name="BasicGauge">
        <attr name="valueTextSize" format="dimension" />
        <attr name="titleTextSize" format="dimension" />
        <attr name="unitsTextSize" format="dimension" />
    </declare-styleable>
</resources>

组件的示例初始化:

<pl.com.digita.BikeComputerUi.customviews.BasicGauge
    android:id="@+id/basicGauge1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:padding="10dp"
    valueTextSize="40sp">

</pl.com.digita.BikeComputerUi.customviews.BasicGauge>

我如何在组件构造函数中尝试读取这些属性:

final int N = typedArray.getIndexCount();
for (int i = 0; i < N; i++) {
    int attribute = typedArray.getIndex(i);
    switch (attribute) {
        case R.styleable.BasicGauge_valueTextSize:
            valueTextSize = typedArray.getString(attribute);
            break;
        case R.styleable.BasicGauge_titleTextSize:
            titleTextSize = typedArray.getString(attribute);
            break;
        case R.styleable.BasicGauge_unitsTextSize:
            unitsTextSize = typedArray.getString(attribute);
            break;
    }
    typedArray.recycle();
}

问题: 创建后,我的所有值仍然为null。40sp正是我所期望的值。

2个回答

72

有几件事要说:

  • 首先,您需要在xml顶部添加一个xml名称空间声明行,就像在android中使用xmlns时一样:xmlns:foo="http://schemas.android.com/apk/res-auto"
  • 然后,您需要使用xmlns前缀来添加valueTextSize:foo:valueTextSize="40sp"

之后,获取字符串并不是一个很好的想法,Android提供了更强大的解决方案来处理尺寸 :

int unitsTextSize = typedArray.getDimensionPixelSize(R.styleable.BasicGauge_unitsTextSize, textSize);

然后还有一些微妙之处:

  • 对于 Paint 或 TextPaint,您可以将此值原样使用:paint.setTextSize(unitTextSize)
  • 对于 TextView,上述方法会失败,您必须使用 setText 的一种重载才能获得正确的结果:textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, unitTextSize);

差异来自于所谓的“原始像素”(未按密度缩放的像素)和“缩放像素”(相反)。


首先 - 感谢您解决我的问题。在复合组件内向TextView传递尺寸值的最佳方法是什么? - piotrpo
你可以这样做:使用自定义属性,在构建复合视图时检索它,然后在创建或填充视图时将其传递给它们。 - Snicolas

38

为了更好地解释已接受的答案:

attrs.xml

使用dimension格式设置自定义属性。

<resources>
    <declare-styleable name="CustomView">
        <attr name="valueTextSize" format="dimension" />
        <attr name="titleTextSize" format="dimension" />
        <attr name="unitsTextSize" format="dimension" />
    </declare-styleable>
</resources>

activity.xml

通过xmlns:app=...引用您的属性,并在xml中使用app:...来设置它们。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <com.example.myproject.CustomView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:valueTextSize="40sp"
        app:titleTextSize="20sp"
        app:unitsTextSize="24sp" /> 

</RelativeLayout>

CustomView.java

使用getDimensionPixelSize从TypedArray获取值。在您的自定义视图中,只使用像素。如果需要转换为其他尺寸,请参见此答案

public class CustomView extends View {

    private float mValueTextSize; // pixels
    private float mTitleTextSize; // pixels
    private float mUnitsTextSize; // pixels

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs, R.styleable.CustomView, 0, 0);
        try {
            mValueTextSize = a.getDimensionPixelSize(R.styleable.CustomView_valueTextSize, 0);
            mTitleTextSize = a.getDimensionPixelSize(R.styleable.CustomView_titleTextSize, 0);
            mUnitsTextSize = a.getDimensionPixelSize(R.styleable.CustomView_unitsTextSize, 0);
        } finally {
            a.recycle();
        }
    }

    // ...
}

1
有人能解释一下为什么在调用getDimensionPixelSize()时我们要将默认值设置为0吗? - Jantzilla
1
@Jantzilla,我不确定为什么将其设置为0。不过你是对的,选择一个更合理的默认值会更好。请记得在运行时针对您选择的任何默认值执行sp转px转换 - Suragch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接