公式 px 到 dp,dp 到 px 机器人

我试图计算一个可变量的像素密度无关的像素,反之亦然。

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

这是 dp 到 px 的公式:

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

有人能给我点建议吗?

177476 次浏览
px = dp * (dpi / 160)


dp = px * (160 / dpi)

你可以使用 [DisplayMatrics][1]来确定屏幕密度,比如:

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

我记得最好使用地板作为偏移量,四舍五入作为宽度。

Px 到 dp:

int valueInpx = ...;
int valueInDp= (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, valueInpx , getResources()
.getDisplayMetrics());

我用以下公式解决了我的问题,希望其他人也能从中受益。

从 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);

注意: 上面广泛使用的解决方案是基于 displayMetrics.density的。然而,文档解释说,这个值是一个四舍五入的值,与屏幕上的“桶”一起使用。例如,在我的 Nexus 10上,它返回2,实际值为298dpi (real)/160dpi (default) = 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 属性,但是我无法想象这些值之间存在很大差异的正常显示。

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

int dpToPx(int dp)
{
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}

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

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

以上所接受的答案并不完全准确,根据检查 Android 源代码所获得的信息:

Resources.getDimension()getDimensionPixelOffset()/getDimensionPixelSize()的区别仅在于前者返回 float,而后两者返回相同的四舍五入到 int的值。对于所有这些方法,返回值都是以原始像素为单位的。

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

因此,如果您想要获得“原始”值和 XML 源代码中指定的单元,那么调用 Resources.getValue()并使用 TypedValue类的方法。

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);


}

如果使用整数,不仅可以避免除以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

在大多数情况下,转换函数经常被调用。我们可以通过增加制表来优化它。因此,它不会每次调用函数时都进行计算。

让我们声明一个 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));
}

谢谢。

使用此功能

private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}

下面的函数在各种设备上都能很好地工作。

它取自 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);
}

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

public static int convertToPixels(Context context, int nDP)
{
final float conversionScale = context.getResources().getDisplayMetrics().density;
return (int) ((nDP * conversionScale) + 0.5f) ;
}

高效的方法

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);
}

希望这个能帮到你。

//用 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));
}

下面是另一种使用 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

使用这些 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()

优雅的 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


.......
}