将像素转换为 dp

Posted

技术标签:

【中文标题】将像素转换为 dp【英文标题】:Converting pixels to dp 【发布时间】:2011-06-04 01:56:36 【问题描述】:

我已经为分辨率为480x800 的 Pantech 设备创建了高度和宽度(以像素为单位)的应用程序。

我需要为 G1 设备转换高度和宽度。 我认为将其转换为 dp 将解决问题并为两种设备提供相同的解决方案。

有什么简单的方法可以? 有什么建议吗?

【问题讨论】:

如果您希望进行一次性转换(例如从 Photoshop 导出精灵),here's a nifty converter。 px, dp, sp conversion formulas web.archive.org/web/20140808234241/http://developer.android.com/… 【参考方案1】:

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

Kotlin 代码:

 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)

【讨论】:

注意:以上是将 DIP 转换为像素。最初的问题是如何将像素转换为 Dips! 这是对 OP 的真实答案:***.com/questions/6656540/… 有趣的是,当它没有真正回答问题时,答案如何更有帮助-_-我以为我想要问题的内容,然后我意识到我没有!这么棒的答案。我确实有一个问题。如何获得applyDimension 的最后一个参数?我可以只做getResource().getDisplayMetrics(),还是有别的事情? 注意:相对昂贵的操作。尝试缓存这些值以便更快地访问 如果无法访问Context 对象,请使用Resources.getSystem().getDisplayMetrics()【参考方案2】:
/**
 * 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);

【讨论】:

可能值得返回一个 int Math.round(px),因为大多数方法都需要一个整数值 @MuhammadBabar 这是因为 160 dpi (mdpi) 是计算其他密度的基准密度。例如,hdpi 被认为是 mdpi 密度的 1.5 倍,这实际上只是 240 dpi 的另一种说法。有关所有密度,请参见下面 Zsolt Safrany 的答案。 @TomTasche:来自Resource.getSystem() 的文档(重点是我的):“返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且未为当前配置屏幕(不能使用尺寸单位,不会因方向等而改变)。” 开发者可以选择上限/下限。最好把控制权交给开发者。 我会推荐 DisplayMetrics.DENSITY_DEFAULT 而不是 160f developer.android.com/reference/android/util/…【参考方案3】:

最好放在一个 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;

【讨论】:

这不适用于所有设备!这个答案的结果与使用 TypedValue.applyDimension 的结果在 OnePlus 3T 上不同(可能是因为 OnePlus 在操作系统中内置了自定义缩放)。使用 TypedValue.applyDimension 会导致跨设备的行为一致。【参考方案4】:
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;

density 等于

.75 on ldpi (120 dpi) 1.0 on mdpi160 dpi;基线) 1.5 on hdpi (240 dpi) 2.0 on xhdpi (320 dpi) 3.0 on xxhdpi (480 dpi) 4.0 on xxxhdpi (640 dpi)

使用此online converter 来调整 dpi 值。

编辑: dpi bucket 和 density 之间似乎没有 1:1 的关系。看起来Nexus 5Xxxhdpidensity 值为2.625(而不是3)。在Device Metrics 中亲自查看。

【讨论】:

“看起来 Nexus 5X 是 xxhdpi,其密度值为 2.6(而不是 3)”- 从技术上讲,Nexus 5X 是 420dpi,而 Nexus 6/6P 是 560dpi,两者都没有直接落入其中标准存储桶,就像带有 tvdpi (213dpi) 的 Nexus 7。因此,将这些列为 xxdpi 和 xxxhdpi 的网站是一场闹剧。您的图表是正确的,这些设备将根据它们的“特殊”dpi 存储桶正确缩放。【参考方案5】:

你可以使用这个.. 没有上下文

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 来做到这一点。这只是我想与您分享的另一种方法

【讨论】:

您可能不想使用它。 getSystem() 的文档 - “返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且未针对当前屏幕进行配置(不能使用维度单位,不会根据方向等进行更改) 。” 接着@Stan 的说法:这很危险,你不应该使用它,尤其是现在设备外形变得如此复杂。 这不考虑可折叠设备和 ChromeOS 设备【参考方案6】:

如果您可以使用尺寸 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);

【讨论】:

由于 px to dp 取决于屏幕密度,我不知道 OP 一开始是如何得到 120 的,除非他或她在所有不同的屏幕尺寸上测试了 px to dp 方法。跨度> 【参考方案7】:

根据 Android 开发指南:

px = dp * (dpi / 160)

但当您收到以像素为单位的设计时,您通常会希望以相反的方式执行此操作。所以:

dp = px / (dpi / 160)

如果您使用的是 240dpi 设备,则该比率为 1.5(如前所述),因此这意味着 60px 图标在应用程序中等于 40dp。

【讨论】:

Indhu,你可以参考这里developer.android.com/guide/practices/…和developer.android.com/reference/android/util/… 160 不变,床答案 @user25 实际上答案很好。你没有在安卓屏幕上阅读过任何文档吗?在谈论 android 屏幕密度时,160 是一个普遍的常数。引用文档:“中等密度(mdpi)屏幕(~160dpi)。(这是基线密度)”。来吧,伙计【参考方案8】:

没有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 说“返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且没有为当前屏幕配置(不能使用维度单位,不根据方向等改变)。”这几乎表明即使它以某种方式有效,您也不应该这样做。 我刚刚阅读了@AustynMahoney 的评论并意识到这个答案并不像我最初想象的那么好,但是SO won't let me undo my upvote!啊!【参考方案9】:

DP to Pixel

dimens.xml中创建一个值

<dimen name="textSize">20dp</dimen>

pixel 中获取该值:

int sizeInPixel = context.getResources().getDimensionPixelSize(R.dimen.textSize);

【讨论】:

【参考方案10】:

对于使用 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

【讨论】:

来自 Resource.getSystem() 的文档:“返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且未针对当前屏幕进行配置(不能使用尺寸单位,不会因方向等而改变)。” @HendraWD 文档可能令人困惑,它提到的维度单位是您的应用程序级别的维度资源。 displayMetrics 不是应用程序级资源。它是一个系统资源,它返回正确的值。此代码在我所有的 Prod 应用程序上运行良好。从来没有问题。 我喜欢这个解决方案,但我最初将逻辑理解为倒退。我想输入 dp 值并说myVal.dp。如果您认为我想要做的事情读​​起来更好,那么您将需要交换除法和乘法逻辑。另外我认为在这里使用roundToInt() 而不是toInt() 会更好。 @AdamJohns 因为所有与视图相关的函数都使用像素作为参数,所以我认为 64.toPx 会更有意义。我将其读取为 64 以转换为像素。但您可以随意更改顺序和名称。最后,重要的部分是是否将值乘以密度。【参考方案11】:

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

【讨论】:

为什么要添加它作为Int的扩展,责任与Int类型无关。 @htafoya 感谢您的反馈。我考虑你在上一版中提到的内容。【参考方案12】:

因此,您可以使用以下公式从 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);

【讨论】:

这会将 dp 转换为像素,但您将方法称为 convertToDp +0.5f 在这里解释 --> developer.android.com/guide/practices/… 。它用于四舍五入到最接近的整数。 唯一正确的答案。你可以添加源developer.android.com/guide/practices/… web.archive.org/web/20140808234241/http://developer.android.com/… 获取仍有问题内容的链接【参考方案13】:

android SDK 中有一个默认的 util: http://developer.android.com/reference/android/util/TypedValue.html

float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())

【讨论】:

你应该使用这个。作为奖励,它也会做 SP。 resultPix 应该是 int 类型。 int resultPix = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())【参考方案14】:

科特林

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)

Java

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

【讨论】:

【参考方案15】:

这应该为您提供 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);

【讨论】:

【参考方案16】:

如果你在 values/dimen 中有维度,最好的方法可能是直接从 getDimension() 方法获取维度,它会返回已经转换为像素值的维度。

context.getResources().getDimension(R.dimen.my_dimension)

只是为了更好地解释这一点,

getDimension(int resourceId) 

将已转换为像素的尺寸作为 FLOAT 返回。

getDimensionPixelSize(int resourceId)

将返回相同但被截断为 int,所以 AS AN 整数。

见Android reference

【讨论】:

【参考方案17】:

像这样:

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;
    

依赖于上下文,返回浮点值,静态方法

来自:https://github.com/Trinea/android-common/blob/master/src/cn/trinea/android/common/util/ScreenUtils.java#L15

【讨论】:

【参考方案18】:

使用 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。 来自 Resource.getSystem() 的文档:“返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且未针对当前屏幕进行配置(不能使用尺寸单位,不会因方向等而改变)。”【参考方案19】:

要将像素转换为 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());

希望有所帮助。

【讨论】:

【参考方案20】:
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);

【讨论】:

这与该问题的许多其他答案所涵盖的内容不一样吗?【参考方案21】:

如果您开发性能关键应用程序,请考虑以下优化类:

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;
    

【讨论】:

只有在您非常频繁地进行转换时才有意义。就我而言,我这样做了。 什么是 160f?为什么用它,为什么是160? 160 => 160dpi,这是因为公式转换度量【参考方案22】:

这对我来说是这样的:

DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int  h = displaymetrics.heightPixels;
float  d = displaymetrics.density;
int heightInPixels=(int) (h/d);

你可以对宽度做同样的事情。

【讨论】:

【参考方案23】:

将 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()。

【讨论】:

答案是错误的,因为您没有将像素转换为 dp - 您正在将像素转换为像素! px2dp 错误 - 将返回相同的像素值。【参考方案24】:

上面有很多很棒的解决方案。不过,我找到的最佳解决方案是 google 的设计:

https://design.google.com/devices/

【讨论】:

【参考方案25】:

您应该像使用像素一样使用 dp。他们就是这样;显示独立像素。使用与中等密度屏幕相同的数字,在高密度屏幕上大小会神奇地正确。

但是,听起来您需要的是布局设计中的 fill_parent 选项。当您希望视图或控件扩展到父容器中的所有剩余大小时,请使用 fill_parent。

【讨论】:

实际上我的问题是我的应用程序是为高密度屏幕编码的,现在它需要转换为低密度屏幕.. 修改中密度屏幕的像素(您可以在模拟器中设置中密度屏幕)并将像素替换为 dp。但是,可以使用 fill_parent 和多个布局来制作更灵活的应用程序。 最后,我别无选择,只能手动将所有 px 更改为 dp.. :( 至少下次你会先使用 dp 并且不需要更改任何东西 :) 虽然应该可以使用大多数事情不需要绝对定位的布局。 因为这是我的第一个应用程序..我犯了这个错误...我再也不会这样做了...:)【参考方案26】:

PXDP 不同但相似。

DP 是仅考虑屏幕物理尺寸时的分辨率。当您使用DP 时,它会将您的布局缩放到具有不同pixel 密度的其他类似大小的屏幕。

虽然有时您实际上需要pixels,但当您处理代码中的维度时,您总是在处理真正的pixels,除非您转换它们。

所以在安卓设备上,正常大小的hdpi 屏幕,800x480 is 533x320 中的DP(我相信)。要将DP 转换为pixels /1.5,再转换回*1.5。这仅适用于一种屏幕尺寸和dpi,它会根据设计而改变。我们的艺术家给了我pixels,然后我用上面的1.5 等式转换为DP

【讨论】:

【参考方案27】:
private fun toDP(context: Context,value: Int): Int 
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
        value.toFloat(),context.resources.displayMetrics).toInt()

【讨论】:

【参考方案28】:

如果您想要 整数 值,则使用 Math.round() 会将浮点数四舍五入为最接近的整数。

public static int pxFromDp(final float dp) 
        return Math.round(dp * Resources.getSystem().getDisplayMetrics().density);
    

【讨论】:

【参考方案29】:

最好的答案来自 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)

【讨论】:

【参考方案30】:

科特林:

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

Java:

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的主要内容,如果未能解决你的问题,请参考以下文章

如何将dp转换为像素,并使用它在android中绘制到画布

如何在 Android Jetpack Compose 中将 Dp 转换为像素?

Android开发之dp转像素,像素转换为dp工具类,详细代码,带有源文件下载地址。

像素 转换 px dp

dp px 像素密度 分辨率

设置宽度(以像素为单位)是不是使用 dp 或 px?