Mengonversi piksel ke dp

827

Saya telah membuat aplikasi saya dengan tinggi dan lebar yang diberikan dalam piksel untuk perangkat Pantech yang resolusinya 480x800.

Saya perlu mengonversi tinggi dan lebar untuk perangkat G1.
Saya pikir mengubahnya menjadi dp akan menyelesaikan masalah dan memberikan solusi yang sama untuk kedua perangkat.

Apakah ada cara mudah untuk mengonversi piksel ke dp?
Ada saran?

Indhu
sumber
1
Jika Anda ingin melakukan konversi satu kali (misalnya untuk mengekspor sprite dari Photoshop), inilah konverter yang bagus .
Paul Lammertsma

Jawaban:

1037
// Converts 14 dip into its equivalent px
float dip = 14f;
Resources r = getResources();
float px = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP,
    dip,
    r.getDisplayMetrics()
);
prasobh
sumber
332
Catatan: Di atas adalah mengkonversi DIP ke Piksel. Pertanyaan awal bertanya bagaimana mengkonversi piksel ke Dips!
Eurig Jones
12
Inilah jawaban nyata untuk OP: stackoverflow.com/questions/6656540/…
qix
119
Lucu bagaimana jawabannya lebih membantu ketika tidak benar-benar menjawab pertanyaan -_- Saya pikir saya ingin apa yang ditanyakan kemudian saya sadar saya tidak melakukannya! Jawabannya sangat bagus. Saya punya pertanyaan. Bagaimana saya bisa mendapatkan parameter terakhir applyDimension? Bisakah saya lakukan getResource().getDisplayMetrics(), atau ada sesuatu yang lain?
Andy
11
CATATAN: operasi yang relatif mahal. Cobalah untuk men-cache nilai untuk akses yang lebih cepat
Entreco
8
Jika tidak memiliki akses ke Contextpenggunaan objekResources.getSystem().getDisplayMetrics()
Farshad Tahmasbi
871
/**
 * 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);
}
Muhammad Nabeel Arif
sumber
8
Mungkin layak mengembalikan int Math.round (px) karena sebagian besar metode mengharapkan nilai integer
Raj Labana
3
@MuhammadBabar Ini karena 160 dpi (mdpi) adalah nilai dasar dari mana kepadatan lain dihitung. hdpi misalnya dianggap 1,5x kepadatan mdpi yang sebenarnya hanyalah cara lain untuk mengatakan 240 dpi. Lihat jawaban Zsolt Safrany di bawah ini untuk semua kepadatan.
Stephen
19
@TomTasche: Dari dokumen untuk Resource.getSystem()(penekanan ranjau): "Kembalikan objek Sumber Daya global bersama yang menyediakan akses ke hanya sumber daya sistem (tanpa sumber daya aplikasi), dan tidak dikonfigurasikan untuk layar saat ini ( tidak dapat menggunakan unit dimensi , tidak berubah berdasarkan orientasi, dll). "
Vicky Chijwani
2
Pengembang memiliki pilihan untuk menambah nilai. Lebih baik memberikan kontrol kepada pengembang.
Muhammad Nabeel Arif
7
Saya akan merekomendasikan DisplayMetrics.DENSITY_DEFAULTbukannya 160f developer.android.com/reference/android/util/…
milcaepsilon
285

Lebih disukai dimasukkan ke dalam kelas 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;
}
Mike Keskinov
sumber
5
Ini tidak berfungsi di semua perangkat! Hasil jawaban ini vs yang menggunakan TypedValue.applyDimension tidak sama pada OnePlus 3T (mungkin karena OnePlus memiliki penskalaan kustom yang dibangun ke dalam OS). Menggunakan TypedValue.applyDimension menyebabkan perilaku konsisten di seluruh perangkat.
Ben De La Haye
197
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;

density sama dengan

  • .75pada ldpi( 120dpi)
  • 1.0pada mdpi( 160dpi; garis dasar)
  • 1.5pada hdpi(240 dpi)
  • 2.0pada xhdpi( 320dpi)
  • 3.0pada xxhdpi( 480dpi)
  • 4.0pada xxxhdpi( 640dpi)

Gunakan konverter online ini untuk bermain-main dengan nilai dpi.

EDIT: Tampaknya tidak ada hubungan 1: 1 antara dpibucket dan density. Sepertinya Nexus 5Xmakhluk xxhdpimemiliki densitynilai 2.625(bukan 3). Lihat sendiri di Metrik Perangkat .

Zsolt Safrany
sumber
3
"Sepertinya Nexus 5X menjadi xxhdpi memiliki nilai kepadatan 2,6 (bukan 3)" - Secara teknis Nexus 5X adalah 420dpi dan Nexus 6/6P adalah 560dpi, tidak ada yang mendarat langsung di salah satu ember standar, seperti halnya Nexus 7 dengan tvdpi (213dpi). Jadi situs yang mencantumkan xxdpi dan xxxhdpi adalah lelucon. Bagan Anda BENAR-BENAR, dan perangkat-perangkat itu akan menskalakan dengan benar satu ember "spesial" dpi mereka.
Steven Byle
108

Anda dapat menggunakan ini .. tanpa Konteks

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

Seperti @Stan disebutkan .. menggunakan pendekatan ini dapat menyebabkan masalah jika sistem mengubah kepadatan. Jadi sadarilah itu!

Secara pribadi saya menggunakan Konteks untuk melakukan itu. Ini hanya pendekatan lain yang ingin saya bagikan kepada Anda

Maher Abuthraa
sumber
11
Anda mungkin tidak ingin menggunakan ini. Dokumentasi untuk getSystem () - "Kembalikan objek Sumber daya global bersama yang menyediakan akses hanya sumber daya sistem (tanpa sumber daya aplikasi), dan tidak dikonfigurasikan untuk layar saat ini (tidak dapat menggunakan unit dimensi, tidak berubah berdasarkan orientasi, dll.) . "
Stan
Menandai apa yang dikatakan @Stan: ini berbahaya dan Anda tidak boleh menggunakannya, terutama sekarang ketika faktor bentuk perangkat menjadi sangat kompleks.
Saket
93

Jika Anda dapat menggunakan dimensi XML, itu sangat sederhana!

Di Anda res/values/dimens.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="thumbnail_height">120dp</dimen>
    ...
    ...
</resources>

Kemudian di Jawa Anda:

getResources().getDimensionPixelSize(R.dimen.thumbnail_height);
Alex
sumber
Karena px ke dp tergantung pada kepadatan layar, saya tidak tahu bagaimana OP mendapatkan 120 di tempat pertama, kecuali dia menguji metode px to dp pada semua ukuran layar yang berbeda.
John61590
75

Menurut Panduan Pengembangan Android:

px = dp * (dpi / 160)

Tetapi seringkali Anda ingin melakukan ini dengan cara sebaliknya ketika Anda menerima desain yang dinyatakan dalam piksel. Begitu:

dp = px / (dpi / 160)

Jika Anda menggunakan perangkat 240dpi, rasio ini adalah 1,5 (seperti yang dinyatakan sebelumnya), jadi ini berarti bahwa ikon 60px sama dengan 40dp dalam aplikasi.

Ricardo Magalhães
sumber
7
160 konstan, jawab tempat tidur
user25
2
@ user25 Sebenarnya jawaban yang bagus. Apakah Anda tidak membaca dokumen di layar android? 160 adalah konstanta umum di semua tempat ketika berbicara tentang kepadatan layar android. Kutipan dari dokumen: "layar kepadatan menengah (mdpi) (~ 160dpi). (Ini adalah kepadatan dasar)". Ayo, teman
mykolaj
70

Tanpa Context, metode statis yang elegan:

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);
}
Adam Stelmaszczyk
sumber
24
Resources.getSystem()javadoc mengatakan "Kembalikan objek Sumber Daya bersama global yang menyediakan akses ke hanya sumber daya sistem (tanpa sumber daya aplikasi), dan tidak dikonfigurasikan untuk layar saat ini (tidak dapat menggunakan unit dimensi, tidak berubah berdasarkan orientasi, dll)." Ini cukup banyak mengatakan Anda tidak harus melakukan ini bahkan jika itu entah bagaimana berhasil.
Austyn Mahoney
Saya baru saja membaca komentar @ AustynMahoney dan menyadari jawaban ini tidak sehebat yang saya kira, tetapi SO tidak akan membiarkan saya membatalkan upvote saya ! Argh!
Vicky Chijwani
45

Untuk DP to Pixel

Buat nilai dalam dimens.xml

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

Dapatkan nilai itu pixelsebagai:

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

Karena itu Anda dapat menggunakan formulator berikut untuk menghitung jumlah piksel yang tepat dari dimensi yang ditentukan dalam 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);
}
neeraj t
sumber
4
Ini mengubah dp menjadi piksel tetapi Anda memanggil metode Anda convertToDp.
Qwertie
4
+ 0.5f dijelaskan di sini -> developer.android.com/guide/practices/… . Ini digunakan untuk membulatkan ke bilangan bulat terdekat.
Bae
satu-satunya jawaban yang benar. Anda dapat menambahkan source developer.android.com/guide/practices/…
user25
web.archive.org/web/20140808234241/http://developer.android.com/... untuk tautan yang masih memiliki konten yang dipermasalahkan
gak
39

Untuk siapa saja yang menggunakan Kotlin:

val Int.toPx: Int
    get() = (this * Resources.getSystem().displayMetrics.density).toInt()

val Int.toDp: Int
    get() = (this / Resources.getSystem().displayMetrics.density).toInt()

Pemakaian:

64.toPx
32.toDp
Gunhan
sumber
Dari dokumen untuk Resource.getSystem (): "Kembalikan objek Sumber Daya global bersama yang menyediakan akses ke hanya sumber daya sistem (tanpa sumber daya aplikasi), dan tidak dikonfigurasikan untuk layar saat ini (tidak dapat menggunakan unit dimensi, tidak berubah berdasarkan pada orientasi, dll). "
HendraWD
@HendraWD Dokumen mungkin membingungkan, unit dimensi yang disebutkan adalah tingkat aplikasi Anda mengurangi sumber daya. displayMetrics bukan sumber daya tingkat aplikasi. Ini adalah sumber daya sistem dan mengembalikan nilai yang benar. Kode ini berfungsi dengan baik di semua aplikasi Prod saya. Tidak pernah memiliki masalah.
Gunhan
33

Ada util default di SDK android: http://developer.android.com/reference/android/util/TypedValue.html

float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
Kvant
sumber
Anda harus menggunakan yang ini. Sebagai bonus juga akan melakukan SP.
Mark Renouf
2
resultPixharus bertipe int. int resultPix = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
vovahost
27

menggunakan kotlin-extension membuatnya lebih baik

fun Int.toPx(context: Context): Int = (this * context.resources.displayMetrics.density).toInt()

fun Int.toDp(context: Context): Int = (this / context.resources.displayMetrics.density).toInt()

MEMPERBARUI:

Karena displayMetricsmerupakan bagian dari Sumber Daya bersama global , kita dapat menggunakanResources.getSystem()

fun Int.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()

fun Int.toDp(): Int = (this / Resources.getSystem().displayMetrics.density).toInt()
beigirad
sumber
4
Mengapa Anda menambahkannya sebagai ekstensi Int, tanggung jawab tidak harus melakukan apa pun dengan tipe Int.
htafoya
19

Ini akan memberi Anda konversi dp ke piksel:

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

Ini akan memberi Anda piksel konversi ke dp:

public static int pxToDp(int px)
{
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
Venki WAR
sumber
19

Kotlin

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

Jawa

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);
}
Khemraj
sumber
12

Mungkin cara terbaik jika Anda memiliki dimensi di dalam nilai / dimen adalah untuk mendapatkan dimensi langsung dari metode getDimension (), itu akan mengembalikan Anda dimensi yang sudah dikonversi menjadi nilai piksel.

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

Untuk lebih menjelaskan hal ini,

getDimension(int resourceId) 

akan mengembalikan dimensi yang sudah dikonversi ke piksel AS A FLOAT.

getDimensionPixelSize(int resourceId)

akan mengembalikan yang sama tetapi terpotong ke int, jadi AS AN INTEGER.

Lihat referensi Android

Lorenzo Barbagli
sumber
9
Untuk mengonversi dp ke piksel.
public static int dp2px(Resources resource, int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,   dp,resource.getDisplayMetrics());
}
Untuk mengonversi piksel ke dp.
  public static float px2dp(Resources resource, float px)  {
    return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}

di mana sumber daya adalah context.getResources ().

Pangeran Gupta
sumber
8
Jawabannya salah, karena Anda tidak mengonversi piksel ke dp - Anda mengonversi piksel ke piksel!
Yaroslav
Px2dp salah - akan mengembalikan nilai yang sama dalam piksel.
natario
8

seperti ini:

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

tergantung pada Konteks, mengembalikan nilai float, metode statis

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

Trinea
sumber
8

Pendekatan yang lebih elegan menggunakan fungsi ekstensi 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()

Pemakaian:

println("16 dp in pixel: ${16.dpToPx}")
println("16 px in dp: ${16.pxToDp}")
Saeed Masoumi
sumber
Senang menggunakan ekstensi di sini. Saya membaca fungsi sebagai "convert to function name" yang saya sadari mundur dalam kasus ini. Untuk memperjelas maksud masing-masing fungsi, nama fungsi dapat diperbarui untuk masing-masing membaca dpToPx dan pxToDp.
Maxwell
Dari dokumen untuk Resource.getSystem (): "Kembalikan objek Sumber Daya global bersama yang menyediakan akses ke hanya sumber daya sistem (tanpa sumber daya aplikasi), dan tidak dikonfigurasikan untuk layar saat ini (tidak dapat menggunakan unit dimensi, tidak berubah berdasarkan pada orientasi, dll). "
HendraWD
7
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);
Sibin
sumber
2
Apakah ini tidak sama dengan apa yang tercakup dalam banyak jawaban lain untuk pertanyaan ini?
TZHX
7

Jika Anda mengembangkan aplikasi penting kinerja, harap pertimbangkan kelas yang dioptimalkan berikut:

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;
    }
}
Pavel
sumber
Masuk akal hanya jika Anda benar-benar melakukan konversi. Dalam kasus saya saya lakukan.
Pavel
Apa 160f? Mengapa Anda menggunakannya, mengapa 160?
dephinera
160 => 160dpi dan ini untuk mengonversi ukuran karena rumus
xAqweRx
6

untuk mengonversi Pixel ke dp gunakan TypedValue .

Seperti yang disebutkan dalam dokumentasi: Wadah untuk nilai data yang diketik secara dinamis.

dan gunakan metode applyDimension :

public static float applyDimension (int unit, float value, DisplayMetrics metrics) 

yang Mengonversi nilai data kompleks yang tidak dibungkus yang menahan dimensi ke nilai titik apung terakhirnya seperti berikut:

Resources resource = getResources();
float dp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 69, resource.getDisplayMetrics());

Semoga Itu Membantu.


sumber
6

Ini cara kerjanya untuk saya:

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

Anda dapat melakukan hal yang sama untuk lebar.

Temi Mide Adey
sumber
4

Anda harus menggunakan dp seperti halnya piksel. Itu saja mereka; menampilkan piksel independen. Gunakan angka yang sama seperti pada layar kepadatan menengah, dan ukurannya akan benar secara ajaib pada layar kepadatan tinggi.

Namun, sepertinya yang Anda butuhkan adalah opsi fill_parent dalam desain tata letak Anda. Gunakan fill_parent ketika Anda ingin tampilan atau kontrol Anda diperluas ke semua ukuran yang tersisa di wadah induk.

Michael Lowman
sumber
sebenarnya masalah saya adalah aplikasi saya dikodekan untuk layar kepadatan tinggi dan sekarang perlu dikonversi ke layar kepadatan rendah ..
Indhu
modifikasi piksel Anda untuk layar kepadatan menengah (Anda dapat mengatur layar kepadatan sedang dalam emulator) dan ganti piksel dengan dp. Namun, aplikasi yang lebih fleksibel dapat dibuat menggunakan fill_parent dan beberapa tata letak.
Michael Lowman
Akhirnya, saya tidak punya pilihan selain mengubah semua px ke dp secara manual .. :(
Indhu
1
Setidaknya lain kali Anda akan menggunakan dp terlebih dahulu dan tidak perlu mengubah apa pun :) Meskipun mungkin untuk menggunakan tata letak yang tidak memerlukan penentuan posisi absolut untuk sebagian besar hal.
Michael Lowman
Karena itu adalah aplikasi pertama saya .. saya membuat kesalahan ini ... saya tidak akan pernah melakukannya lagi ... :)
Indhu
4

PXdan DPberbeda tetapi serupa.

DPadalah resolusi ketika Anda hanya memperhitungkan ukuran fisik layar. Ketika Anda menggunakannya DPakan mengatur tata letak Anda ke layar berukuran serupa lainnya dengan pixelkepadatan berbeda .

Kadang-kadang Anda benar-benar ingin pixels, dan ketika Anda berurusan dengan dimensi dalam kode Anda selalu berurusan dengan nyata pixels, kecuali jika Anda mengubahnya.

Jadi pada perangkat android, hdpilayar berukuran normal , 800x480 is 533x320di DP(saya percaya). Untuk mengkonversi DPmenjadi pixels /1.5, untuk mengkonversi kembali *1.5. Ini hanya untuk satu ukuran layar dan dpi, itu akan berubah tergantung pada desain. Artis kami memberi saya pixelsdan saya beralih ke DPdengan 1.5persamaan di atas .

HaMMeReD
sumber
3

Jika Anda ingin nilai Integer maka menggunakan Math.round () akan mengitari float ke integer terdekat.

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

Jawaban terbaik datang dari kerangka kerja Android itu sendiri: cukup gunakan persamaan ini ...

public static int dpToPixels(final DisplayMetrics display_metrics, final float dps) {
    final float scale = display_metrics.density;
    return (int) (dps * scale + 0.5f);
}

(mengkonversi dp ke px)

JarsOfJam-Scheduler
sumber
2

Workds ini untuk saya (C #):

int pixels = (int)((dp) * Resources.System.DisplayMetrics.Density + 0.5f);
Michael Zhang
sumber
Bukan jawaban untuk pertanyaan ini tetapi untuk C # itu berfungsi. Terima kasih
Yekmer Simsek
2

kotlin

   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
}

Jawa

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