数式pxからdp、dpからpx android


150

私は、密度に依存しないピクセルとその逆のピクセルの可変量を計算しようとしています。

この式(px to dp): dp = (int)(px / (displayMetrics.densityDpi / 160));はゼロで除算されるため、小さなデバイスでは機能しません。

これは私のdpからpxの式です:

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

誰かが私にいくつかの指針を与えることができますか?


1
ピクセル単位にDP単位変換developer.android.com/guide/practices/...
パドマクマー

@ブラム:私はあなたの公式は大丈夫だと思う。どのようにしてゼロによる除算を取得しますか?displayMetrics.densityDpiは決して0、120、160、240または320のいずれかであろう
ct_rob

@ct_robに同意します。displayMetrics.densityDpi / 160最小値は0.75になります。間違った場所でintにキャストしている必要があります。
TomTaila、2017

回答:


318

注:上記で広く使用されているソリューションはに基づいてい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のプロパティがあるので、区別した方がいいかもしれませんが、これらの値が大きく異なる正気なディスプレイは想像できません。


8
これは、多くのデバイス(Nexus 10を含む)のdp / pxの正しい値を計算しません!あなたが言うように、displayMetrics.densityは最も近い画面バケットに丸められますが、dpユニットもそうです!160dp幅のオブジェクトを1つ描画してみて、そのすぐ下にdpToPx(160)ピクセル幅の別のオブジェクトを描画すると、2つのオブジェクトのサイズが異なることがわかります。また、一部の電話(Galaxy MiniやGalaxy S3 Miniなど)は、xdpi / ydpiに対して完全に誤った値を報告するため、これらの電話ではメソッドが完全に誤った結果を返します。
nibarius

@nibariusはい、Androidのボックス化dp計算と上記の計算を混在させることはできません。上記のソリューションは、正確なデバイス物理に基づいた、密度に依存しない個別の値を意味します。たとえば、さまざまなデバイスで正確に同じ実際の長さの線を表示したい場合に必要です。もちろん、一部のデバイスでxdpi / ydpi入力が正しく設定されていないと、そこで機能しません。
バチ14

1
xdpiとydpiは、多くのデバイスで不正確である場合があるため、使用しないでください。信頼性が高いのはDisplayMetrics.densityDpiのみですが、設計上不正確であるため、残念です。詳細については、Googleフォーラムのスレッドを参照してください:groups.google.com/forum
Mark McClelland

1
私はこの応答を見つけ、実際に多くの同様のソリューションを使用しましたが、ドキュメントを調べたところ、手作りのコードと同じように、ディメンション(dip / dpで宣言)を指定してgetDimensionPixelOffSetがオフセットをピクセルで返すことがわかりました。私はテストして完璧に動作しました。それが役に立てば幸い!
william gouvea 14

1
まあ、これは正しい値を与えません。試してみてください:リソースr = getResources(); float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP、14、r.getDisplayMetrics()); ここで説明されているように:stackoverflow.com/questions/4605527/converting-pixels-to-dp
Rik van Velzen

103

以下の計算式で解決しました。他の人々がそれから利益を得ることができますように。

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

27
@Vame 0.5の加算は、最も近い整数値に切り上げるために使用されます。0.5が加算されてから、計算結果がintとしてキャストされ、仮数が切り捨てられ、特性は適切に丸められた整数値として残されます。
ケリーコプリー

3
これは常に正しいとは限りません。2つのレイアウトが互いに内側にあり、各ビューの角を丸めると(1つはdpを使用し、もう1つはdpに変換します)、角が一致しません!
Marek

私はこのテクニックで何の問題もありませんでした。これをさまざまなレイアウトに使用しましたが、常に期待どおりに機能しました。もちろん、私は数年前にこれを使用しましたが、それがまだ機能するかどうかはわかりません。おそらく、PanaVTECの答えで他の手法を試すことができます。また、dp / pxの計算だけではなく、角を丸めることのほうが多い場合もあります。
Bram

5
これはAndroidデベロッパーサイトで採用されているものと同じソリューションであるため、正しいと思います:)。http://developer.android.com/guide/practices/screens_support.html#dips-pels
alocaly 14

1
+1ありがとうございます。魅力のように働いた!このソリューションを共有していただきありがとうございます。
Simon Dorociak 2014年

34

pxからdpへ:

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

7
これはDPからPXへの変更ですが、この修正によりtypedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, valueInDp , getResources() .getDisplayMetrics());、PXからDPへ、これも最良の回答です
PaNaVTEC

1
@ PaNaVTEC、dpからpxに参照したソリューションは正しくありません。applyDimensionピクセルのみを生成します。android.googlesource.com/platform/frameworks/base/+/refs/heads/…を参照してくださいCOMPLEX_UNIT_PX。変換は行われません。
Stephen Niedzielski 2015

この答えは間違いです。最終値をピクセル単位で返しますdp。ソースコードを見ると、ケースTypedValue.COMPLEX_UNIT_DIPvalue * metrics.densityは、実際に必要な場所が返されますvalue * metrics.density。それでは、あなたはvalueInDp`をgetting`ていることではありませんdpvalueInPxの中でpx
bitbybit

^ typo、value / metrics.density
つまり

31

今までにない効率的な方法

DPからPixel:

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

これがお役に立てば幸いです。


4
コンテキストを使用する必要がないため、より良い:)ありがとう。
Ayaz Alifov 2017年

2
ベストアンサー!残念ながら、「正しいとマークされています」という答えは間違っています。特に、displayMetrics.xdpiどのデバイスでも異なるものを使用しているためです。悲しいことに、この間違った答えはさらに賛成票が最も多くなります。
toom '16

いいね。ベストアンサーとしてマークする必要があります。kotlin:private fun dpToPx(dp: Int) = (dp * Resources.getSystem().displayMetrics.density).toInt()
ラファエルC

28

呼び出すだけでgetResources().getDimensionPixelSize(R.dimen.your_dimension)dp単位をピクセルに変換できます


3
ドキュメントによれば、これはgetDimension()と同じですが、戻り値がサイズとして使用するために整数ピクセルに変換されます。サイズ変換では、ベース値を丸め、ゼロ以外のベース値のサイズが少なくとも1ピクセルになるようにします。
CJBS 2015

14

この機能を使用

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

6
px = dp * (dpi / 160)

dp = px * (160 / dpi)

しかし、今私はそれについて考えています...ブラムスオリジナルの公式でゼロによる分裂がどのようにありますか?displayMetrics.densityDpiは決して0、120、160、240または320のいずれかであろう
ct_rob

2
(displayMetrics.densityDpi / 160)-この部分は、小さなデバイスでは0を取得できます。そこで計算されます。たとえば120/160、両方の値がintであり、結果は0になります(int) (px/0)

ああ、あなたは正しい。すべてのように彼は、ISが長く彼の式で使用し実行する必要があります160.0
ct_rob

DisplayMetrics.DENSITY_DEFAULTには160個の値があるため、この答えは上の答えと似ています。しかし、DPIの計算方法を教えてください。
ジョンスミス

3

ほとんどの場合、変換関数は頻繁に呼び出されます。メモ化を追加することで最適化できます。そのため、関数が呼び出されるたびに計算されるわけではありません。

計算された値を格納する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));
}

ありがとう。


与えられたソリューションへの素晴らしい追加。
Bram

同期計算は言うまでもなく、変換計算がマップルックアップほど高速でなかったとしたら驚きます。この最適化が有益であることを示すテスト結果はありますか?作業メモリが限られているAndroidでは、計算作業のためのメモリの交換は、正当な理由なしに行うべきものではありません。
Lorne Laliberte


2

以下の機能は、さまざまなデバイスでうまく機能しました。

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

1

[DisplayMatrics][1]画面密度を使用して決定できます。このようなもの:

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

覚えているように、オフセットにはフローリングを使用し、幅には丸めを使用することをお勧めします。



1

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

1

次の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()

0

私が書いたこの方法を自由に使ってください:

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

0

上記で受け入れられた答えは完全に正確ではありません。Androidのソースコードを調べて得られた情報によると:

Resources.getDimension()およびgetDimensionPixelOffset()/ getDimensionPixelSize()は、前者が戻りfloat、後者の2つはint適切に丸められた同じ値を返すという点でのみ異なります。それらすべての場合、戻り値は生のピクセル単位です。

3つすべての関数は、を呼び出しResources.getValue()て変換することによって実装され、とをTypedValue呼び出して取得します。TypedValue.complexToDimension()TypedValue.complexToDimensionPixelOffset()TypedValue.complexToDimensionPixelSize()

したがって、XMLソースで指定された単位と一緒に「生の」値を取得する場合Resources.getValue()は、TypedValueクラスのメソッドを呼び出して使用します。


0

他の答えの助けを借りて、私はこの関数を書きました。

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

0

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

0
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

上記のct_robsの回答のバリエーション。整数を使用している場合、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.