ChatGPT解决这个技术问题 Extra ChatGPT

将像素转换为 dp

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

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

有什么简单的方法可以将像素转换为 dp?有什么建议么?

如果您希望进行一次性转换(例如从 Photoshop 导出精灵),here's a nifty converter

H
Hani

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)

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

最好放入 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 会导致跨设备的行为一致。
Z
Zsolt Safrany
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 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 存储桶正确缩放。
M
Maher Abuthraa

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

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 设备
T
Tim

如果您可以使用尺寸 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 方法。
L
Linga

根据Android开发指南:

px = dp * (dpi / 160)

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

dp = px / (dpi / 160)

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


160不变,床答
user25 实际上答案很好。你没有在安卓屏幕上阅读过任何文档吗?在谈论 android 屏幕密度时,160 是一个普遍的常数。引用文档:“中等密度(mdpi)屏幕(~160dpi)。(这是基线密度)”。来吧,伙计
A
Adam Stelmaszczyk

没有 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!啊!
b
beigirad

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

更新:

由于 displayMetricsglobal 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 设备。


为什么要将它添加为 Int 的扩展,责任不必对 Int 类型做任何事情。
@htafoya 感谢您的反馈。我考虑你在上一版中的提及。
您不应为此使用 Resources.getSystem(),因为它不处理可折叠设备和 Chrome OS 设备。
K
Kapil Rajput

对于DP to Pixel

dimens.xml 中创建一个值

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

pixel 中获取该值:

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

G
Gunhan

对于使用 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 以转换为像素。但您可以随意更改顺序和名称。最后,重要的部分是是否将值乘以密度。
您不应该为此使用 Resources.getSystem() 。
t
tabjsina

因此,您可以使用以下公式从 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/…
Y
Yan

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())
K
Khemraj Sharma

科特林

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

S
Saravanabalagi Ramachandran

这应该给你转换 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);
}

您不应该为此使用 Resources.getSystem() 。
L
Lorenzo Barbagli

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

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

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

getDimension(int resourceId) 

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

getDimensionPixelSize(int resourceId)

将返回相同但截断为 int,因此作为整数。

请参阅Android reference


T
Trinea

像这样:

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


佚名

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

希望有帮助。


x
xlecoustillier
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);

这与该问题的许多其他答案所涵盖的内容不一样吗?
P
Pavel

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

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,这是因为公式转换度量
S
Saeed Masoumi

使用 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() 的文档:“返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且未针对当前屏幕进行配置(不能使用维度单位,不会根据方向等)。”
您不应该为此使用 Resources.getSystem() 。
J
Jared Rummler

这对我来说是这样的:

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

您可以对宽度执行相同的操作。


K
Kai Wang

上面有很多很棒的解决方案。但是,我找到的最佳解决方案是谷歌的设计:

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

https://i.stack.imgur.com/nuoMF.png


M
Manaus

将 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 错误 - 将返回相同的像素值。
M
Max Base

科特林:

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

M
Michael Lowman

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

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


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

PXDP 不同但相似。

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

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

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


A
Alexander
private fun toDP(context: Context,value: Int): Int {
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
        value.toFloat(),context.resources.displayMetrics).toInt()
}

H
Hitesh Sahu

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

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

J
JarsOfJam-Scheduler

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