161

我正在尝试将可变数量的像素计算为与密度无关的像素,反之亦然。

此公式(px to dp): dp = (int)(px / (displayMetrics.densityDpi / 160));不适用于小型设备,因为它被零除。

这是我的 dp 到 px 公式:

px = (int)(dp * (displayMetrics.densityDpi / 160));

有人可以给我一些指示吗?

4

21 回答 21

328

注意:上面广泛使用的解决方案是基于displayMetrics.density. 但是,文档解释说这个值是一个四舍五入的值,与屏幕“桶”一起使用。例如。在我的 Nexus 10 上,它返回 2,其中实际值为 298dpi(真实)/160dpi(默认)= 1.8625。

根据您的要求,您可能需要精确的转换,可以这样实现:

[编辑] 这并不意味着与 Android 的内部 dp 单元混合,因为这当然仍然基于屏幕存储桶。在您想要一个在不同设备上呈现相同实际尺寸的单元时使用它。

将 dp 转换为像素:

public int dpToPx(int dp) {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));     
}

将像素转换为 dp:

public int pxToDp(int px) {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}

请注意,有 xdpi 和 ydpi 属性,您可能想要区分,但我无法想象这些值差异很大的理智显示。

于 2013-07-01T17:17:51.687 回答
104

我使用以下公式解决了我的问题。愿其他人从中受益。

dp 到 px:

displayMetrics = context.getResources().getDisplayMetrics();
return (int)((dp * displayMetrics.density) + 0.5);

px 到 dp:

displayMetrics = context.getResources().getDisplayMetrics();
return (int) ((px/displayMetrics.density)+0.5);
于 2011-12-13T13:55:00.747 回答
43

高效的方式

DP 到像素:

private int dpToPx(int dp)
{
    return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}

像素到 DP:

private int pxToDp(int px)
{
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}

希望这会帮助你。

于 2016-01-13T10:04:40.340 回答
36

px 到 dp:

int valueInpx = ...;
int valueInDp= (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, valueInpx , getResources()
                .getDisplayMetrics());
于 2011-11-29T11:08:28.487 回答
29

只需调用getResources().getDimensionPixelSize(R.dimen.your_dimension)即可将dp单位转换为像素

于 2014-02-20T15:24:22.633 回答
14

使用此功能

private int dp2px(int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
于 2015-06-19T09:24:53.833 回答
6
px = dp * (dpi / 160)

dp = px * (160 / dpi)
于 2011-11-29T10:54:50.963 回答
5

使用这些 Kotlin 扩展:

/**
 * Converts Pixel to DP.
 */
val Int.pxToDp: Int
    get() = (this / Resources.getSystem().displayMetrics.density).toInt()

/**
 * Converts DP to Pixel.
 */
val Int.dpToPx: Int
    get() = (this * Resources.getSystem().displayMetrics.density).toInt()
于 2019-12-25T14:17:52.867 回答
3

在大多数情况下,转换函数被频繁调用。我们可以通过添加 memoization 来优化它。因此,它不会在每次调用函数时进行计算。

让我们声明一个 HashMap 来存储计算的值。

private static Map<Float, Float> pxCache = new HashMap<>();

计算像素值的函数:

public static float calculateDpToPixel(float dp, Context context) {

        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        float px = dp * (metrics.densityDpi / 160f);
        return px;

    }

一个记忆函数,它从 HashMap 返回值并维护先前值的记录。

记忆化可以在 Java 中以不同的方式实现。对于 Java 7

public static float convertDpToPixel(float dp, final Context context) {

        Float f = pxCache.get(dp);
        if (f == null) {
            synchronized (pxCache) {
                f = calculateDpToPixel(dp, context);
                pxCache.put(dp, f);
            }

        }

        return f;
    }

Java 8 支持 Lambda 函数

public static float convertDpToPixel(float dp, final Context context) {

        pxCache.computeIfAbsent(dp, y ->calculateDpToPixel(dp,context));
}

谢谢。

于 2015-02-26T06:52:32.697 回答
2

试试这个 http://labs.skinkers.com/content/android_dp_px_calculator/

于 2011-11-29T12:46:43.307 回答
2

下面的功能对我来说在各种设备上都很有效。

它取自https://gist.github.com/laaptu/7867851

public static float convertPixelsToDp(float px){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float dp = px / (metrics.densityDpi / 160f);
    return Math.round(dp);
}

public static float convertDpToPixel(float dp){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return Math.round(px);
}
于 2015-11-13T05:16:44.817 回答
1

您可以使用[DisplayMatrics][1]和确定屏幕密度。像这样的东西:

int pixelsValue = 5; // margin in pixels
float d = context.getResources().getDisplayMetrics().density;
int margin = (int)(pixelsValue * d);

我记得最好使用地板进行偏移和四舍五入的宽度。

于 2011-11-29T11:00:07.217 回答
1

如果您正在寻找一种在线计算器,用于在不同的屏幕密度下相互转换 DP、SP、英寸、毫米、点或像素,这是我所知道的最完整的工具

于 2014-06-11T10:08:03.893 回答
1

// 用于获取 Decimal/Float

public static float convertPixelsToDp(float px, Context context) {

    Resources resources = context.getResources();
    DisplayMetrics metrics = resources.getDisplayMetrics();
    float dp = px / (metrics.densityDpi / 160f);
    return Math.round(dp);
}



public static float convertDpToPixel(float dp, Context context) {
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return Math.round(px);
}


// for  getting in terms of Integer

private int convertPxToDp(int px, Context context) {
    Resources resources = context.getResources();
    return Math.round(px / (resources.getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
}


private int convertDpToPx(int dp, Context context) {
    Resources resources = context.getResources();

    return Math.round(dp * (resources.getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));

}

________________________________________________________________________________

public static float convertPixelsToDp(float px){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float dp = px / (metrics.densityDpi / 160f);
    return Math.round(dp);
}

public static float convertDpToPixel(float dp){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return Math.round(px);
}


private int convertDpToPx(int dp){
    return Math.round(dp*(getResources().getDisplayMetrics().xdpi/DisplayMetrics.DENSITY_DEFAULT));

}

private int convertPxToDp(int px){
    return Math.round(px/(Resources.getSystem().getDisplayMetrics().xdpi/DisplayMetrics.DENSITY_DEFAULT));
}
于 2016-09-21T12:08:00.390 回答
1

优雅的 kotlin 解决方案 :)

val Int.dp get() = this / (Resources.getSystem().displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
val Float.dp get() = this / (Resources.getSystem().displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)

val Int.px get() = this * Resources.getSystem().displayMetrics.density
val Float.px get() = this * Resources.getSystem().displayMetrics.density

用法:

val dpValue = 2.dp
val pxFromDpValue = 2.px

重要的:

我不确定是否Resources.getSystem()可以在方向更改时正常工作。

如果想在例如片段或活动中工作,只需将其添加到基本片段或基本活动中并像这样使用它:

abstract class BaseFragment : Fragment() {

    val Int.dp get() = this / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
    val Float.dp get() = this / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)

    val Int.px get() = this * resources.displayMetrics.density
    val Float.px get() = this * resources.displayMetrics.density

    .......
}
于 2021-11-11T11:59:15.527 回答
0

随意使用我写的这个方法:

int dpToPx(int dp)
{
    return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}
于 2013-07-10T22:02:25.587 回答
0

上面接受的答案并不完全准确。根据查看Android源码得到的信息:

Resources.getDimension()getDimensionPixelOffset()/getDimensionPixelSize()不同之处仅在于前者返回float,而后两者返回相同的值,四舍五入到int适当的程度。对于所有这些,返回值都是原始像素。

这三个函数都是通过调用和转换来实现的,分别调用,和Resources.getValue()得到。TypedValueTypedValue.complexToDimension()TypedValue.complexToDimensionPixelOffset()TypedValue.complexToDimensionPixelSize()

因此,如果要获取“原始”值以及 XML 源中指定的单位,请调用Resources.getValue()并使用TypedValue该类的方法。

于 2014-09-01T16:01:48.337 回答
0
DisplayMetrics displayMetrics = contaxt.getResources()
            .getDisplayMetrics();

    int densityDpi = (int) (displayMetrics.density * 160f);
    int ratio = (densityDpi / DisplayMetrics.DENSITY_DEFAULT);
    int px;
    if (ratio == 0) {
        px = dp;
    } else {
        px = Math.round(dp * ratio);

    }
于 2014-09-17T10:24:12.697 回答
0

上面 ct_robs 答案的变体,如果您使用整数,不仅可以避免除以 0,还可以在小型设备上产生可用的结果:

在涉及最高精度除法的整数计算中,在除法之前先乘以减少截断效应。

px = dp * dpi / 160
dp = px * 160 / dpi

5 * 120 = 600 / 160 = 3

代替

5 * (120 / 160 = 0) = 0

如果您想要四舍五入的结果,请执行此操作

px = (10 * dp * dpi / 160 + 5) / 10
dp = (10 * px * 160 / dpi + 5) / 10

10 * 5 * 120 = 6000 / 160 = 37 + 5 = 42 / 10 = 4
于 2015-01-31T22:52:20.060 回答
0

在其他答案的帮助下,我编写了这个函数。

public static int convertToPixels(Context context, int nDP)
{
        final float conversionScale = context.getResources().getDisplayMetrics().density; 
        return (int) ((nDP * conversionScale) + 0.5f) ;
}
于 2016-01-05T05:36:24.203 回答
0

这是使用 kotlin 扩展的另一种方法:

val Int.dpToPx: Int
    get() = Math.round(this * Resources.getSystem().displayMetrics.density)

val Int.pxToDp: Int
    get() = Math.round(this / Resources.getSystem().displayMetrics.density)

然后它可以在任何地方像这样使用

12.dpToPx

244.pxToDp
于 2019-03-28T19:55:51.987 回答