我正在尝试计算可变数量的像素到密度无关像素和反之。
这个公式 (px转dp): dp = (int)(px / (displayMetrics.densityDpi / 160));
在小设备上不起作用,因为它会被零除。
这是我的dp转px公式:
px = (int)(dp * (displayMetrics.densityDpi / 160));
有人能给我一些指针吗?
我正在尝试计算可变数量的像素到密度无关像素和反之。
这个公式 (px转dp): dp = (int)(px / (displayMetrics.densityDpi / 160));
在小设备上不起作用,因为它会被零除。
这是我的dp转px公式:
px = (int)(dp * (displayMetrics.densityDpi / 160));
有人能给我一些指针吗?
注意:上面广泛使用的解决方案基于 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属性,您可能需要进行区分,但我无法想象一个理智的显示器,在这些值有很大差异的情况下。
我通过使用以下公式解决了我的问题。希望其他人也能从中受益。
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);
从 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);
}
希望这能对你有所帮助。
displayMetrics.xdpi
在任何设备上都是不同的。遗憾的是,这个错误的答案还有最多的赞数。 - toomResources.getSystem()
并不总是正确的。 - EpicPandaForcepx转dp:
int valueInpx = ...;
int valueInDp= (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, valueInpx , getResources()
.getDisplayMetrics());
typedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, valueInDp , getResources().getDisplayMetrics());
。这也是最佳答案。 - PaNaVTECapplyDimension
只会返回像素值。请参考https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/util/TypedValue.java#344,其中`COMPLEX_UNIT_PX`没有进行任何转换。 - Stephen Niedzielskidp
。如果你查看源代码,在 TypedValue.COMPLEX_UNIT_DIP
的情况下,返回的是 value * metrics.density
,而实际上你需要的是 value * metrics.density
。所以,你得到的 valueInDp
并不是 dp
,而是 px
中的 valueInPx
。 - bitbybitvalue / metrics.density
的地方"_ - bitbybit只需调用getResources().getDimensionPixelSize(R.dimen.your_dimension)
即可将单位从dp
转换为像素
使用此函数
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
使用以下 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()
px = dp * (dpi / 160)
dp = px * (160 / dpi)
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));
}
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
.......
}