我为分辨率为 480x800
的 Pantech 设备创建了我的应用程序,其高度和宽度以像素为单位。
我需要为 G1 设备转换高度和宽度。我认为将其转换为 dp 将解决问题并为两种设备提供相同的解决方案。
有什么简单的方法可以将像素转换为 dp?有什么建议么?
Java代码:
// Converts 14 dip into its equivalent px
float dip = 14f;
Resources r = getResources();
float px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dip,
r.getDisplayMetrics()
);
科特林代码:
val dip = 14f
val r: Resources = resources
val px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dip,
r.displayMetrics
)
Kotlin 扩展:
val Number.toPx get() = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this.toFloat(),
Resources.getSystem().displayMetrics)
/**
* This method converts dp unit to equivalent pixels, depending on device density.
*
* @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
* @param context Context to get resources and device specific display metrics
* @return A float value to represent px equivalent to dp depending on device density
*/
public static float convertDpToPixel(float dp, Context context){
return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
/**
* This method converts device specific pixels to density independent pixels.
*
* @param px A value in px (pixels) unit. Which we need to convert into db
* @param context Context to get resources and device specific display metrics
* @return A float value to represent dp equivalent to px value
*/
public static float convertPixelsToDp(float px, Context context){
return px / ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
Resource.getSystem()
的文档(强调我的):“返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且未针对当前屏幕进行配置(不能使用尺寸单位,不会因方向等而改变)。”
最好放入 Util.java 类
public static float dpFromPx(final Context context, final float px) {
return px / context.getResources().getDisplayMetrics().density;
}
public static float pxFromDp(final Context context, final float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;
density
等于
.75 在 ldpi (120 dpi)
1.0 on mdpi(160 dpi;基线)
1.5 在 hdpi (240 dpi)
2.0 xhdpi (320 dpi)
3.0 在 xxhdpi (480 dpi)
4.0 在 xxxhdpi (640 dpi)
使用此 online converter 来处理 dpi 值。
编辑:dpi
存储桶和 density
之间似乎没有 1:1 的关系。看起来 Nexus 5X
是 xxhdpi
的 density
值为 2.625
(而不是 3
)。请在 Device Metrics 中亲自查看。
你可以使用这个 .. 没有上下文
public static int pxToDp(int px) {
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
正如@Stan 提到的......如果系统改变密度,使用这种方法可能会导致问题。所以要注意这一点!
就我个人而言,我正在使用 Context 来做到这一点。这只是我想与您分享的另一种方法
如果您可以使用尺寸 XML,那就很简单了!
在您的 res/values/dimens.xml
中:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="thumbnail_height">120dp</dimen>
...
...
</resources>
然后在你的 Java 中:
getResources().getDimensionPixelSize(R.dimen.thumbnail_height);
根据Android开发指南:
px = dp * (dpi / 160)
但是,当您收到以像素为单位的设计时,您通常会希望以相反的方式执行此操作。所以:
dp = px / (dpi / 160)
如果您使用的是 240dpi 设备,则此比率为 1.5(如前所述),因此这意味着 60px 图标在应用程序中等于 40dp。
没有 Context
,优雅的静态方法:
public static int dpToPx(int dp)
{
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
public static int pxToDp(int px)
{
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
Resources.getSystem()
javadoc 说“返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且未针对当前屏幕进行配置(不能使用维度单位,不根据方向更改等)。 "这几乎说明你不应该这样做,即使它以某种方式有效。
使用 kotlin-extension 让它变得更好
fun Int.toPx(context: Context): Int = (this * context.resources.displayMetrics.density).toInt()
fun Int.toDp(context: Context): Int = (this / context.resources.displayMetrics.density).toInt()
更新:
由于 displayMetrics
是 global shared Resources 的一部分,我们可以使用 Resources.getSystem()
val Float.toPx get() = this * Resources.getSystem().displayMetrics.density
val Float.toDp get() = this / Resources.getSystem().displayMetrics.density
val Int.toPx get() = (this * Resources.getSystem().displayMetrics.density).toInt()
val Int.toDp get() = (this / Resources.getSystem().displayMetrics.density).toInt()
PS:根据@EpicPandaForce 的评论:
您不应该为此使用 Resources.getSystem(),因为它不处理可折叠设备和 Chrome OS 设备。
Resources.getSystem()
,因为它不处理可折叠设备和 Chrome OS 设备。
对于DP to Pixel
在 dimens.xml
中创建一个值
<dimen name="textSize">20dp</dimen>
在 pixel
中获取该值:
int sizeInPixel = context.getResources().getDimensionPixelSize(R.dimen.textSize);
对于使用 Kotlin 的任何人:
val Int.toPx: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
val Int.toDp: Int
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
用法:
64.toPx
32.toDp
myVal.dp
。如果您认为我想要做的事情读起来更好,那么您将需要交换除法和乘法逻辑。另外我认为在这里使用 roundToInt()
而不是 toInt()
会更好一些。
因此,您可以使用以下公式从 dp 中指定的维度计算正确的像素数量
public int convertToPx(int dp) {
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (dp * scale + 0.5f);
}
convertToDp
。
android SDK 中有一个默认的 util:http://developer.android.com/reference/android/util/TypedValue.html
float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
resultPix
应该是 int 类型。 int resultPix = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
科特林
fun convertDpToPixel(dp: Float, context: Context): Float {
return dp * (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}
fun convertPixelsToDp(px: Float, context: Context): Float {
return px / (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}
爪哇
public static float convertDpToPixel(float dp, Context context) {
return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
public static float convertPixelsToDp(float px, Context context) {
return px / ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
这应该给你转换 dp 到像素:
public static int dpToPx(int dp)
{
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
这应该为您提供到 dp 的转换像素:
public static int pxToDp(int px)
{
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
如果您在 values/dimen 中有维度,最好的方法可能是直接从 getDimension() 方法获取维度,它将返回已经转换为像素值的维度。
context.getResources().getDimension(R.dimen.my_dimension)
只是为了更好地解释这一点,
getDimension(int resourceId)
将返回已转换为像素的尺寸作为 FLOAT。
getDimensionPixelSize(int resourceId)
将返回相同但截断为 int,因此作为整数。
像这样:
public class ScreenUtils {
public static float dpToPx(Context context, float dp) {
if (context == null) {
return -1;
}
return dp * context.getResources().getDisplayMetrics().density;
}
public static float pxToDp(Context context, float px) {
if (context == null) {
return -1;
}
return px / context.getResources().getDisplayMetrics().density;
}
}
依赖于上下文,返回浮点值,静态方法
将像素转换为 dp 使用 TypedValue 。
如文档所述:动态类型数据值的容器。
并使用 applyDimension 方法:
public static float applyDimension (int unit, float value, DisplayMetrics metrics)
它将保存维度的解压缩复杂数据值转换为其最终浮点值,如下所示:
Resources resource = getResources();
float dp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 69, resource.getDisplayMetrics());
希望有帮助。
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);
如果您开发性能关键应用程序,请考虑以下优化类:
public final class DimensionUtils {
private static boolean isInitialised = false;
private static float pixelsPerOneDp;
// Suppress default constructor for noninstantiability.
private DimensionUtils() {
throw new AssertionError();
}
private static void initialise(View view) {
pixelsPerOneDp = view.getResources().getDisplayMetrics().densityDpi / 160f;
isInitialised = true;
}
public static float pxToDp(View view, float px) {
if (!isInitialised) {
initialise(view);
}
return px / pixelsPerOneDp;
}
public static float dpToPx(View view, float dp) {
if (!isInitialised) {
initialise(view);
}
return dp * pixelsPerOneDp;
}
}
使用 kotlin 的扩展函数更优雅的方法
/**
* Converts dp to pixel
*/
val Int.dpToPx: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()
/**
* Converts pixel to dp
*/
val Int.pxToDp: Int get() = (this / Resources.getSystem().displayMetrics.density).toInt()
用法:
println("16 dp in pixel: ${16.dpToPx}")
println("16 px in dp: ${16.pxToDp}")
function name
”,在这种情况下我意识到这是倒退的。为了阐明每个函数的意图,函数的名称可以更新为分别读取 dpToPx 和 pxToDp。
这对我来说是这样的:
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int h = displaymetrics.heightPixels;
float d = displaymetrics.density;
int heightInPixels=(int) (h/d);
您可以对宽度执行相同的操作。
上面有很多很棒的解决方案。但是,我找到的最佳解决方案是谷歌的设计:
https://design.google.com/devices/
https://i.stack.imgur.com/nuoMF.png
将 dp 转换为像素
public static int dp2px(Resources resource, int dp) {
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,resource.getDisplayMetrics()
);
}
将像素转换为 dp。
public static float px2dp(Resources resource, float px) {
return (float)TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX,
px,
resource.getDisplayMetrics()
);
}
其中资源是 context.getResources()。
科特林:
fun spToPx(ctx: Context, sp: Float): Float {
return sp * ctx.resources.displayMetrics.scaledDensity
}
fun pxToDp(context: Context, px: Float): Float {
return px / context.resources.displayMetrics.density
}
fun dpToPx(context: Context, dp: Float): Float {
return dp * context.resources.displayMetrics.density
}
爪哇:
public static float spToPx(Context ctx,float sp){
return sp * ctx.getResources().getDisplayMetrics().scaledDensity;
}
public static float pxToDp(final Context context, final float px) {
return px / context.getResources().getDisplayMetrics().density;
}
public static float dpToPx(final Context context, final float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
您应该像使用像素一样使用 dp 。他们就是这样;显示独立像素。在中等密度屏幕上使用相同的数字,在高密度屏幕上大小会神奇地正确。
但是,听起来您需要的是布局设计中的 fill_parent 选项。当您希望视图或控件扩展到父容器中的所有剩余大小时,请使用 fill_parent。
PX
和 DP
不同但相似。
DP
是仅考虑屏幕物理尺寸时的分辨率。当您使用 DP
时,它会将您的布局缩放到具有不同 pixel
密度的其他类似尺寸的屏幕。
但有时您实际上需要 pixels
,当您在代码中处理维度时,您总是在处理真正的 pixels
,除非您转换它们。
所以在 Android 设备上,正常大小的 hdpi
屏幕,800x480 is 533x320
在 DP
(我相信)。要将 DP
转换为 pixels /1.5
,再转换回 *1.5
。这仅适用于一种屏幕尺寸和dpi
,它会根据设计而改变。我们的艺术家给了我 pixels
,我用上面的 1.5
等式转换为 DP
。
private fun toDP(context: Context,value: Int): Int {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
value.toFloat(),context.resources.displayMetrics).toInt()
}
如果你想要整数值,那么使用 Math.round() 会将浮点数四舍五入到最接近的整数。
public static int pxFromDp(final float dp) {
return Math.round(dp * Resources.getSystem().getDisplayMetrics().density);
}
最好的答案来自 Android 框架本身:只需使用这个相等性...
public static int dpToPixels(final DisplayMetrics display_metrics, final float dps) {
final float scale = display_metrics.density;
return (int) (dps * scale + 0.5f);
}
(将 dp 转换为 px)
applyDimension
的最后一个参数?我可以只做getResource().getDisplayMetrics()
,还是有别的?Context
对象,请使用Resources.getSystem().getDisplayMetrics()