从源代码中加载res/values/dimension.xml中的尺寸值

424

我想要以原封不动的方式加载这个值。 我有两个dimension.xml文件,一个在/res/values/dimension.xml中,另一个在/res/values-sw360dp/dimension.xml中。

从源代码中,我想要做一些类似于:

getResources().getDimension(R.dimen.tutorial_cross_marginTop);

这个方法可行,但我得到的值会乘以屏幕密度因子(例如hdpi为1.5,xhdpi为2.0等)。

我还尝试过做以下操作

getResources().getString(R.dimen.tutorial_cross_marginTop);

这原则上可以工作,但是我得到的字符串最后以"dip"结尾...


1
我想知道这是否是Android中的一个bug,因为Resources类有一个方法getDimensionPixelSize(int id)明确说明它返回像素值,因此getDimension(int id)应该返回独立于依赖关系的单位(dp),以便可以直接使用,例如在View的setPadding方法中。 - Paul Verest
@PaulVerest 我也对API中的冗余感到困惑,但既然现在是2022年,而且API文档说明所有方法都返回“像素”,我想这应该是预期行为。 - mdelolmo
11个回答

966

在我的dimens.xml文件中,我有:

<dimen name="test">48dp</dimen>

在代码中,如果我这样做:

int valueInPixels = (int) getResources().getDimension(R.dimen.test)

这将返回72,正如文档所述,它会乘以当前手机的密度(在我的情况下为48dp x 1.5)。

与文档完全一致:

检索特定资源ID的尺寸。单位转换基于与资源相关联的当前DisplayMetrics。

因此,如果您想要像xml中一样精确的dp值,只需将其除以DisplayMetrics密度即可。

int dp = (int) (getResources().getDimension(R.dimen.test) / getResources().getDisplayMetrics().density);

现在dp将会是48


4
我觉得这里的文档特别不清楚。"Unit conversions are based on the current DisplayMetrics associated with the resources." 的意思只是想说它们转换成像素。 - Trilarion
如果您基本上要放弃显示度量乘数,那么最好只需以px定义您的尺寸。<dimen name="test">48px</dimen>。getDimension(R.dimen.test)将返回48。 - Michael Peterson
对我无效:https://stackoverflow.com/questions/55972518/not-correct-return-text-size-in-sp - Alex
@Trilarion,它们不仅仅是转换为像素。他们说dp将给出相对于用于检索它的资源对象的比例缩放像素值。一旦你进入各种获取资源的方式,这将更加相关。为简单起见,您可以认为它是相对于屏幕比例的。还有sp,或者相对于系统文本大小的像素,以及px,或者直接像素。每个都不同,具有不同的目的。 - Abandoned Cart
如果您想从dimens.xml获取sp值,则需要int sp = (int) (getResources().getDimension(R.dimen.test) / getResources().getDisplayMetrics().scaledDensity)。 - Seven

24
Context.getResources().getDimension(int id);

21

对于那些只需要在资源中保存一些 int 值的人,可以按照以下步骤进行操作。

integers.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="default_value">100</integer>
</resources> 

代码

int defaultValue = getResources().getInteger(R.integer.default_value);

3
谢谢你,这正是我需要的,虽然可能不适用于其他人,但是这个解决方案实际上为我提供了一些有关代码其他方面的见解。 - JamisonMan111

19

26
这是错误的!如果您参考文档,就会发现在getDimensionPixelSize()中也进行度量转换。显式说明如下: 返回 “资源尺寸值乘以适当的度量单位,并截断为整数像素。” - Muhammad Babar
这是错误的。度量转换也使用这种方法进行。 - Michael Peterson

15

您可以使用 getDimensionPixelOffset() 而不是 getDimension,这样就不必转换为整数。

int valueInPixels = getResources().getDimensionPixelOffset(R.dimen.test)

14

使用Kotlin扩展

您可以添加一个扩展来简化此过程。它使您只需调用context.dp(R.dimen.tutorial_cross_marginTop)即可获取Float值。

fun Context.px(@DimenRes dimen: Int): Int = resources.getDimension(dimen).toInt()

fun Context.dp(@DimenRes dimen: Int): Float = px(dimen) / resources.displayMetrics.density

如果您想在没有上下文的情况下处理它,可以使用Resources.getSystem()

val Int.dp get() = this / Resources.getSystem().displayMetrics.density // Float

val Int.px get() = (this * Resources.getSystem().displayMetrics.density).toInt()
例如,在xhdpi设备上,使用24.dp可获得12.0或使用12.px可获得24。

9

这里有一个更好的解决方案,不需要从dp转为px再从px转为dp进行双重转换:

Kotlin中的实现

fun Resources.getRawDimensionInDp(@DimenRes dimenResId: Int): Float {
    val value = TypedValue()
    getValue(dimenResId, value, true)
    return TypedValue.complexToFloat(value.data)
}
// Usage: 
resources.getRawDimensionInDp(R.dimen.my_dimen_id)

在Java中

public class ResourcesUtil {
    static Float getRawDimensionInDp(Resources resources, @DimenRes int dimenResId) {
        TypedValue value = new TypedValue();
        resources.getValue(dimenResId, value, true);
        return TypedValue.complexToFloat(value.data);
    }
}

// Usage: 
ResourcesUtil.getRawDimensionInDp(resources, R.dimen.my_dimen_id);

5

3
我为此编写了两个在kotlin中的辅助函数。
/**
 * Gets the float value defined in dimens
 * Define float value as following
 * Example:
 * <item name="example" format="float" type="dimen">1.0</item>
 */
fun Resources.getFloatDimension(dimensResourceId: Int): Float {
    val outValue = TypedValue()
    this.getValue(dimensResourceId, outValue, true)
    return outValue.float
}

/**
 * Gets the dp value defined in dimens
 * Example:
 * <dimen name="example">12dp</dimen>
 *
 * Will return 12
 */
fun Resources.getDimensionInDp(dimensResourceId: Int): Int {
    return (getDimension(dimensResourceId) / displayMetrics.density).toInt()
}

2
如果您只想动态更改字体大小,则可以执行以下操作:
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.tutorial_cross_marginTop))

如@achie所述,您可以从dimens.xml中获取dp值,方法如下:

val dpValue = (resources.getDimension(R.dimen.tutorial_cross_marginTop)/ resources.displayMetrics.density).toInt()

或者像这样获取sp。
val spValue = (resources.getDimension(R.dimen.font_size)/ resources.displayMetrics.scaledDensity).toInt()

About Resources.java #{getDimension}

    /**
     * Retrieve a dimensional for a particular resource ID.  Unit 
     * conversions are based on the current {@link DisplayMetrics} associated
     * with the resources.
     * 
     * @param id The desired resource identifier, as generated by the aapt
     *           tool. This integer encodes the package, type, and resource
     *           entry. The value 0 is an invalid identifier.
     * 
     * @return Resource dimension value multiplied by the appropriate 
     * metric.
     * 
     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
     *
     * @see #getDimensionPixelOffset
     * @see #getDimensionPixelSize
     */

资源维度值乘以适当的

技术。

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