Formula px ke dp, dp ke px android

150

Saya mencoba menghitung jumlah variabel piksel ke piksel independen dan sebaliknya.

Formula (px to dp): dp = (int)(px / (displayMetrics.densityDpi / 160));ini tidak berfungsi pada perangkat kecil karena dibagi dengan nol.

Ini adalah formula dp to px saya:

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

Bisakah seseorang memberi saya beberapa petunjuk?

Bram
sumber
1
Mengubah unit dp ke unit pixel developer.android.com/guide/practices/…
Padma Kumar
@Ram: Saya pikir formula Anda baik-baik saja. Bagaimana Anda akan mendapatkan divisi dengan nol? displayMetrics.densityDpi akan menjadi 120, 160, 240 atau 320, tidak pernah 0.
ct_rob
Saya setuju dengan @ct_rob. displayMetrics.densityDpi / 160 nilai minimum akan menjadi 0,75. Anda pasti casting ke int di tempat yang salah.
TomTaila

Jawaban:

318

Catatan: Solusi yang banyak digunakan di atas didasarkan pada displayMetrics.density. Namun, dokumen menjelaskan bahwa nilai ini adalah nilai bulat, digunakan dengan layar 'ember'. Misalnya. pada Nexus 10 saya mengembalikan 2, di mana nilai sebenarnya adalah 298dpi (real) / 160dpi (default) = 1.8625.

Tergantung pada kebutuhan Anda, Anda mungkin memerlukan transformasi yang tepat, yang dapat dicapai seperti ini:

[Sunting] Ini tidak dimaksudkan untuk dicampur dengan unit dp internal Android, karena hal ini tentu saja masih berdasarkan pada ember layar. Gunakan ini di mana Anda menginginkan unit yang harus merender ukuran sebenarnya yang sama pada perangkat yang berbeda.

Konversi dp ke piksel:

public int dpToPx(int dp) {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));     
}

Konversikan piksel ke dp:

public int pxToDp(int px) {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}

Perhatikan bahwa ada properti xdpi dan ydpi, Anda mungkin ingin membedakan, tapi saya tidak bisa membayangkan tampilan waras di mana nilai-nilai ini sangat berbeda.

Bachi
sumber
8
Ini tidak akan menghitung nilai yang benar untuk dp / px pada banyak perangkat (termasuk Nexus 10 Anda)! Seperti yang Anda katakan displayMetrics.density dibulatkan ke ember layar terdekat, tetapi begitu juga unit dp! Cobalah menggambar satu objek yang lebar 160dp dan tepat di bawahnya Anda menggambar objek lain yang lebar dpToPx (160) piksel dan Anda akan melihat bahwa ukuran kedua objek berbeda. Juga beberapa telepon (seperti Galaxy Mini dan Galaxy S3 Mini) melaporkan nilai yang sepenuhnya salah untuk xdpi / ydpi sehingga pada ponsel ini metode Anda akan mengembalikan hasil yang benar-benar salah.
nibarius
@nibarius Ya Anda tidak dapat mencampur perhitungan dp kotak Android dengan yang di atas. Solusi di atas dimaksudkan sebagai nilai independen kepadatan terpisah berdasarkan fisika perangkat yang tepat. Diperlukan misalnya di mana Anda ingin menunjukkan garis panjang sebenarnya sama persis pada perangkat yang berbeda. Tentu saja jika input xdpi / ydpi tidak diatur dengan benar oleh beberapa perangkat, itu tidak akan berfungsi di sana.
Bachi
1
xdpi dan ydpi tidak boleh digunakan, karena mereka tidak akurat pada banyak perangkat, kadang-kadang oleh banyak. Hanya DisplayMetrics.densityDpi yang dapat diandalkan, yang sangat disayangkan, karena desainnya tidak tepat. Lihat utas forum Google untuk info lebih lanjut: groups.google.com/forum/#!topic/android-developers/g56jV0Hora0
Mark McClelland
1
Saya menemukan respons ini dan benar-benar menggunakan banyak solusi serupa tetapi saya hanya memeriksa dokumen dan menemukan getDimensionPixelOffSet dengan memberikan dimensi (dinyatakan dalam dip / dp) mengembalikan offset dalam piksel seperti kode buatan tangan. Saya menguji dan bekerja dengan sempurna. Semoga ini bisa membantu!
william gouvea
1
Mehhh, ini tidak memberikan nilai yang benar. Coba: Sumber Daya r = getResources (); float px = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 14, r.getDisplayMetrics ()); Seperti dijelaskan di sini: stackoverflow.com/questions/4605527/converting-pixels-to-dp
Rik van Velzen
103

Saya memecahkan masalah saya dengan menggunakan rumus berikut. Semoga orang lain mendapat manfaat darinya.

dp ke px:

displayMetrics = context.getResources().getDisplayMetrics();
return (int)((dp * displayMetrics.density) + 0.5);

px ke dp:

displayMetrics = context.getResources().getDisplayMetrics();
return (int) ((px/displayMetrics.density)+0.5);
Bram
sumber
27
@Vame Penambahan 0,5 digunakan untuk membulatkan UP ke nilai integer terdekat .. 0,5 ditambahkan dan kemudian hasil perhitungan dilemparkan sebagai int yang menyebabkannya memotong mantissa dan meninggalkan karakteristik sebagai nilai integer yang dibulatkan dengan benar.
Kelly Copley
3
Ini tidak selalu benar. Ketika saya memiliki dua tata letak satu di dalam yang lain dan kemudian saya membulatkan sudut setiap tampilan (satu dengan menggunakan dp, yang lain dikonversi ke dp) sudut tidak cocok!
Marek
Saya tidak punya masalah dengan teknik ini. Saya menggunakan ini untuk tata letak yang berbeda dan selalu berfungsi seperti yang diharapkan. Tentu saja saya menggunakan ini beberapa tahun yang lalu dan saya tidak yakin apakah itu masih berfungsi. Mungkin Anda bisa mencoba teknik lain dalam jawaban PanaVTEC. Bisa juga bahwa ada lebih banyak sudut pembulatan dari sekedar perhitungan dp / px.
Bram
5
Ini solusi yang sama yang diadopsi di situs pengembang Android, jadi saya kira itu benar :). http://developer.android.com/guide/practices/screens_support.html#dips-pels
alocaly
1
+1 Terima kasih kawan. Bekerja seperti pesona! Terima kasih telah berbagi solusi ini dengan kami.
Simon Dorociak
34

px ke dp:

int valueInpx = ...;
int valueInDp= (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, valueInpx , getResources()
                .getDisplayMetrics());
Kannan Suresh
sumber
7
Ini dari DP ke PX, tetapi dengan koreksi ini: typedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, valueInDp , getResources() .getDisplayMetrics());dari PX ke DP, juga ini adalah jawaban terbaik
PaNaVTEC
1
@ PaaaVTEC, solusi yang Anda rujuk untuk dp ke px salah. applyDimensionhanya menghasilkan piksel. Lihat android.googlesource.com/platform/frameworks/base/+/refs/heads/… di mana konversi tidak dilakukan COMPLEX_UNIT_PX.
Stephen Niedzielski
Jawaban ini jelas salah. Ini mengembalikan nilai akhir dalam piksel, tidak pernah dalam dp. Jika Anda melihat kode sumber, untuk kasus ini TypedValue.COMPLEX_UNIT_DIP, value * metrics.densitydikembalikan, di mana Anda benar-benar perlu value * metrics.density. Jadi, apa yang Anda peroleh `valueInDp` BUKAN dpuntuk valueInPxmasuk px.
bitbybit
^ salah ketik, maksud saya "... di mana Anda benar-benar membutuhkan value / metrics.density"
bitbybit
31

Cara yang efisien

DP ke Pixel:

private int dpToPx(int dp)
{
    return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}

Piksel ke DP:

private int pxToDp(int px)
{
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}

Semoga ini bisa membantu Anda.

Hiren Patel
sumber
4
Lebih baik karena tidak perlu menggunakan Konteks :) Terima kasih.
Ayaz Alifov
2
Jawaban Terbaik! Sayangnya jawaban "Ditandai sebagai benar" salah. Terutama karena ia menggunakan displayMetrics.xdpiyang berbeda pada perangkat apa pun. Sayangnya, jawaban yang salah ini juga paling banyak mendapat dukungan.
toom
bagus. harus ditandai sebagai jawaban terbaik. kotlin:private fun dpToPx(dp: Int) = (dp * Resources.getSystem().displayMetrics.density).toInt()
Raphael C
28

Panggil saja getResources().getDimensionPixelSize(R.dimen.your_dimension)untuk mengonversi dari dpsatuan ke piksel

pelotasplus
sumber
3
Per dokumentasi, ini sama dengan getDimension (), kecuali nilai yang dikembalikan dikonversi ke piksel integer untuk digunakan sebagai ukuran. Konversi ukuran melibatkan pembulatan nilai dasar, dan memastikan bahwa nilai dasar non-nol setidaknya satu piksel dalam ukuran.
CJBS
14

Gunakan fungsi ini

private int dp2px(int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
Prashant Maheshwari Andro
sumber
6
px = dp * (dpi / 160)

dp = px * (160 / dpi)
ct_rob
sumber
meskipun, sekarang saya berpikir tentang hal itu ... bagaimana mungkin ada ramalan dengan nol dalam formula asli Brams? displayMetrics.densityDpi akan menjadi 120, 160, 240 atau 320, tidak pernah 0.
ct_rob
2
(displayMetrics.densityDpi / 160)- bagian ini bisa mendapatkan 0 pada perangkat kecil, di sana ia menghitung misalnya 120/160, kedua nilai int, yang menghasilkan 0. Yang berakhir sebagai (int) (px/0).
ah kamu benar Jadi yang perlu dia lakukan adalah menggunakan panjang dalam formulanya:
160.0
jawaban ini mirip dengan yang teratas karena DisplayMetrics.DENSITY_DEFAULT memiliki nilai 160. tapi tolong beri tahu kami apa DPI di sini bagaimana kami menghitungnya.
John smith
3

Dalam sebagian besar kasus, fungsi konversi sering dipanggil. Kami dapat mengoptimalkannya dengan menambahkan memoisasi. Jadi, itu tidak menghitung setiap kali fungsi dipanggil.

Mari mendeklarasikan HashMap yang akan menyimpan nilai yang dihitung.

private static Map<Float, Float> pxCache = new HashMap<>();

Fungsi yang menghitung nilai piksel:

public static float calculateDpToPixel(float dp, Context context) {

        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        float px = dp * (metrics.densityDpi / 160f);
        return px;

    }

Fungsi memoisasi yang mengembalikan nilai dari HashMap dan memelihara catatan nilai sebelumnya.

Memoisasi dapat diimplementasikan dengan berbagai cara di Jawa. Untuk 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 mendukung fungsi Lambda :

public static float convertDpToPixel(float dp, final Context context) {

        pxCache.computeIfAbsent(dp, y ->calculateDpToPixel(dp,context));
}

Terima kasih.

Parth mehta
sumber
tambahan yang bagus untuk solusi yang diberikan.
Bram
Saya akan terkejut jika perhitungan konversi tidak setidaknya secepat pencarian peta, belum lagi yang disinkronkan. Apakah Anda memiliki hasil tes untuk menunjukkan optimasi ini bermanfaat? Pada Android yang memori kerjanya terbatas, perdagangan memori untuk upaya perhitungan bukanlah sesuatu yang harus Anda lakukan tanpa alasan yang kuat.
Lorne Laliberte
2

Fungsi di bawah berfungsi dengan baik untuk saya di seluruh perangkat.

Ini diambil dari 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);
}
Blesson Jose
sumber
1

Anda dapat menggunakan [DisplayMatrics][1]dan menentukan kepadatan layar. Sesuatu seperti ini:

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

Seingat saya lebih baik menggunakan lantai untuk offset dan pembulatan untuk lebar.

Houcine
sumber
1

Jika Anda mencari kalkulator daring untuk mengonversi DP, SP, inci, milimeter, titik atau piksel ke dan dari satu sama lain pada kepadatan layar yang berbeda, ini adalah alat paling lengkap yang saya tahu .

Paul Lammertsma
sumber
1

// untuk mendapatkan dalam bentuk Desimal / 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));
}
Trinadh Koya
sumber
1

Gunakan ekstensi Kotlin ini:

/**
 * 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()
Malwinder Singh
sumber
0

Jangan ragu untuk menggunakan metode ini yang saya tulis:

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

Jawaban yang diterima di atas tidak sepenuhnya akurat. Menurut informasi yang diperoleh dengan memeriksa kode sumber Android:

Resources.getDimension()dan getDimensionPixelOffset()/ getDimensionPixelSize()hanya berbeda dalam hal pengembalian yang pertama floatsedangkan yang kedua mengembalikan nilai yang sama dibulatkan menjadi inttepat. Untuk semuanya, nilai kembaliannya dalam piksel mentah.

Ketiga fungsi diimplementasikan dengan memanggil Resources.getValue()dan mengkonversi sehingga diperoleh TypedValuedengan memanggil TypedValue.complexToDimension(), TypedValue.complexToDimensionPixelOffset()dan TypedValue.complexToDimensionPixelSize(), masing-masing.

Oleh karena itu, jika Anda ingin mendapatkan nilai "mentah" bersama dengan unit yang ditentukan dalam sumber XML, panggil Resources.getValue()dan gunakan metode TypedValuekelas.

Jaromír Adamec
sumber
0

dengan bantuan jawaban lain saya menulis fungsi ini.

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

Berikut cara lain untuk melakukannya menggunakan ekstensi 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)

dan kemudian dapat digunakan seperti ini dari mana saja

12.dpToPx

244.pxToDp
Quinn
sumber
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);

    }
Sushil Mittal
sumber
0

variasi jawaban ct_robs di atas, jika Anda menggunakan bilangan bulat, yang tidak hanya menghindari bagi dengan 0, juga menghasilkan hasil yang dapat digunakan pada perangkat kecil:

dalam perhitungan bilangan bulat yang melibatkan pembagian untuk penggandaan presisi terbesar terlebih dahulu sebelum membaginya untuk mengurangi efek pemotongan.

px = dp * dpi / 160
dp = px * 160 / dpi

5 * 120 = 600 / 160 = 3

dari pada

5 * (120 / 160 = 0) = 0

jika Anda ingin hasil bulat lakukan ini

px = (10 * dp * dpi / 160 + 5) / 10
dp = (10 * px * 160 / dpi + 5) / 10

10 * 5 * 120 = 6000 / 160 = 37 + 5 = 42 / 10 = 4
pengguna2624395
sumber