Pikselleri dp'ye dönüştürme


826

Uygulamamı, çözünürlüğü olan bir Pantech cihazı için piksel cinsinden verilen yükseklik ve genişlikle oluşturdum 480x800.

Bir G1 cihazı için yükseklik ve genişliği dönüştürmem gerekiyor.
Ben dp dönüştürmek sorunu çözecek ve her iki cihaz için aynı çözümü sağlayacaktır düşündüm.

Pikselleri dp'ye dönüştürmenin kolay bir yolu var mı?
Herhangi bir öneri?


1
Bir kerelik bir dönüşüm yapmak istiyorsanız (örneğin Photoshop'tan spriteları dışa aktarmak için), şık bir dönüştürücü .
Paul Lammertsma


Yanıtlar:


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

332
Not: Yukarıdaki DIP'leri Piksellere dönüştürüyor. Orijinal soru pikselleri Dips'e nasıl dönüştüreceğini sordu!
Eurig Jones

12
İşte
OP'ye

119
Bu gerçekten soruyu gerçekten cevaplamadığında cevabın nasıl daha yararlı olduğunu -_- Sorunun sorulmasını istediğimi düşündüm o zaman ben fark ettim! Harika bir cevap. Bir sorum var. Son parametreyi nasıl elde edebilirim applyDimension? Sadece yapabilir miyim getResource().getDisplayMetrics(), yoksa başka bir şey var mı?
Andy

11
NOT / BILGI: nispeten pahalı çalışma. Daha hızlı erişim için değerleri önbelleklemeye çalışın
Entreco

8
ContextNesne kullanımına erişiminiz yoksaResources.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);
}

8
Çoğu yöntem bir tamsayı değeri beklediğinden int Math.round (px) döndürmeye değer olabilir
Raj Labana

3
@MuhammadBabar Bunun nedeni 160 dpi (mdpi) 'nin diğer yoğunlukların hesaplandığı temel desity olmasıdır. Örneğin hdpi, 240 dpi söylemenin başka bir yolu olan mdpi yoğunluğunun 1.5 katı olarak kabul edilir. Tüm yoğunluklar için aşağıdaki Zsolt Safrany cevabına bakınız.
Stephen

19
@TomTasche: Resource.getSystem()(vurgu mayını) için dokümanlardan : "Yalnızca sistem kaynaklarına erişim sağlayan (uygulama kaynakları yok) ve geçerli ekran için yapılandırılmamış ( boyut birimleri kullanılamıyor , değişmiyor ) global paylaşılan Kaynaklar nesnesini döndürme yönelime dayalı, vb.) "
Vicky Chijwani

2
Geliştirici değeri tavan / taban için bir seçim var. Geliştiriciye kontrol vermek daha iyidir.
Muhammed Nabeel Arif

7
Ben salık DisplayMetrics.DENSITY_DEFAULTyerine 160f developer.android.com/reference/android/util/...
milcaepsilon

285

Tercihen bir Util.java sınıfına

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

5
Bu, tüm cihazlarda çalışmaz! Bu cevabın sonucu TypedValue.applyDimension kullanmanın bir OnePlus 3T'de aynı değildir (muhtemelen OnePlus'ın işletim sistemine yerleşik özel ölçeklendirmesi olduğu için). TypedValue.applyDimension kullanmak, aygıtlar arasında tutarlı davranışlara neden olur.
Ben De La Haye

197
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;

density eşittir

  • .75açık ldpi( 120dpi)
  • 1.0açık mdpi( 160dpi; taban çizgisi)
  • 1.5açık hdpi( 240dpi)
  • 2.0açık xhdpi( 320dpi)
  • 3.0açık xxhdpi( 480dpi)
  • 4.0açık xxxhdpi( 640dpi)

Dpi değerleriyle oynamak için bu çevrimiçi dönüştürücüyü kullanın .

EDIT: Görünüşe göre dpikova ve arasında 1: 1 bir ilişki yoktur density. Öyle görünüyor Nexus 5Xvarlık xxhdpibir sahiptir densitydeğerini 2.625(yerine 3). Cihaz Metrikleri'nde kendiniz görün .


3
"Nexus 5X'in xxhdpi olması 2.6 (3 yerine) yoğunluk değerine sahip" Tvdpi (213dpi) ile Nexus 7. Yani xxdpi ve xxxhdpi olarak listeleyen site bir saçmalık. Grafiğiniz doğrudur ve bu cihazlar "özel" dpi gruplarına göre doğru şekilde ölçeklenir.
Steven Byle

108

Bunu .. Bağlam olmadan kullanabilirsiniz

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'ın belirttiği gibi .. bu yaklaşımı kullanmak, sistem yoğunluğunu değiştirirse soruna neden olabilir. Öyleyse bunun farkında olun!

Şahsen bunu yapmak için Bağlam kullanıyorum. Sizi paylaşmak istediğim başka bir yaklaşım.


11
Bunu kullanmak istemeyebilirsiniz. GetSystem () - "Yalnızca sistem kaynaklarına erişim sağlayan (uygulama kaynağı yok) ve geçerli ekran için yapılandırılmamış (boyut birimleri kullanılamıyor, yönlendirmeye bağlı olarak değişmeyen vb.) Bir genel paylaşılan Kaynaklar nesnesini döndürme ."
Stan

@Stan'ın söylediklerine ikinci olarak: bu tehlikeli ve özellikle de cihaz form faktörleri çok karmaşık hale geldiğinde kullanmamalısınız.
Saket

93

XML boyutlarını kullanabiliyorsanız çok basit!

Sizin res/values/dimens.xml:

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

Sonra Java'nızda:

getResources().getDimensionPixelSize(R.dimen.thumbnail_height);

Dp'den dp'ye ekran yoğunluğuna bağlı olduğundan, tüm farklı ekran boyutlarında px-dp yöntemini test etmedikçe OP'nin ilk etapta nasıl 120 olduğunu bilmiyorum.
John61590

75

Android Geliştirme Kılavuzu'na göre:

px = dp * (dpi / 160)

Ancak, genellikle piksel cinsinden bir tasarım aldığınızda bunu tersine yapmak istersiniz. Yani:

dp = px / (dpi / 160)

240dpi bir cihaz kullanıyorsanız, bu oran 1,5'tir (daha önce belirtildiği gibi), bu da 60px simgesinin uygulamada 40dp'ye eşit olduğu anlamına gelir.


2
Indhu, Burada geliştirici.android.com/ guide/practices/… ve geliştirici.android.com/
Sachchidanand

7
160 sabittir, yatak cevabı
user25

2
@ user25 Gerçekten harika bir cevap. Android ekranlarda herhangi bir doküman okumadınız mı? Android ekran yoğunlukları hakkında konuşurken 160 her yerde ortak bir sabittir. Dokümanlardan alıntı: "orta yoğunluklu (mdpi) ekranlar (~ 160dpi). (Bu taban yoğunluğu)." Hadi adamım
mykolaj

70

ContextZarif statik yöntemler olmadan :

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

24
Resources.getSystem()javadoc, "Yalnızca sistem kaynaklarına erişim sağlayan (uygulama kaynağı yok) ve geçerli ekran için yapılandırılmamış (boyut birimlerini kullanamaz, yönlendirmeye bağlı olarak değişmez, vb.) bir genel paylaşılan Kaynaklar nesnesini döndür." Bu hemen hemen bir şekilde çalışıyor olsa bile bunu yapmamanız gerektiğini söylüyor.
Austyn Mahoney

Sadece @ AustynMahoney'in yorumunu okudum ve bu cevabın aslında düşündüğüm kadar büyük olmadığını fark ettim, ama SO benim oyumu geri almama izin vermiyor ! Ahh!
Vicky Chijwani

45

İçin DP to Pixel

İçinde bir değer oluşturun dimens.xml

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

Bu değeri şu şekilde alın pixel:

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

39

Bu nedenle, dp'de belirtilen bir boyuttan doğru piksel miktarını hesaplamak için aşağıdaki formülü kullanabilirsiniz.

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

4
Bu, dp'yi piksele dönüştürür, ancak yönteminizi çağırdınız convertToDp.
Qwertie

4
+ 0.5f burada açıklanmaktadır -> developer.android.com/guide/practices/… . En yakın tam sayıya yuvarlamak için kullanılır.
Bae


hala söz konusu içeriğe sahip bir bağlantı için web.archive.org/web/20140808234241/http://developer.android.com/…
caw

39

Kotlin kullanan herkes için:

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

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

Kullanımı:

64.toPx
32.toDp

Resource.getSystem () için dokümanlardan: "Yalnızca sistem kaynaklarına erişim sağlayan (uygulama kaynağı yok) ve geçerli ekran için yapılandırılmamış (boyut birimleri kullanılamıyor, yönlendirme vb.) "
HendraWD

@HendraWD Belgeler kafa karıştırıcı olabilir, bahsettiği boyut birimleri uygulama seviyeniz kaynakları azaltır. displayMetrics, uygulama düzeyinde bir kaynak değildir. Bir sistem kaynağıdır ve doğru değerleri döndürür. Bu kod, tüm Prod uygulamalarımda iyi çalışıyor. Hiç bir sorun yaşamadım.
Günhan


27

kotlin-extension kullanmak daha iyi hale getirir

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

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

GÜNCELLEME:

Çünkü displayMetricsbir parçasıdır küresel paylaşılan Kaynaklar , biz kullanabilirsinizResources.getSystem()

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

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

4
Neden Int'nin bir uzantısı olarak eklesiniz, sorumluluk Int türüyle ilgili bir şey yapmak zorunda değildir.
19:34, htafoya

19

Bu size dp'yi piksele dönüştürme işlemini vermelidir:

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

Bu size dp'ye dönüşüm piksellerini vermelidir:

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

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

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

12

Muhtemelen en iyi yol, değerler / dimen içindeki boyutunuz varsa, boyutu doğrudan getDimension () yönteminden elde etmektir, size zaten piksel değerine dönüştürülmüş boyutu döndürür.

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

Bunu daha iyi açıklamak için,

getDimension(int resourceId) 

FLOAT OLARAK zaten piksele dönüştürülmüş boyutu döndürür.

getDimensionPixelSize(int resourceId)

aynı döndürür ama int kısaltılır, böylece bir INTEGER OLARAK.

Android referansına bakın


9
Dp'yi piksele dönüştürmek için.
public static int dp2px(Resources resource, int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,   dp,resource.getDisplayMetrics());
}
Piksel dönüştürmek için dp.
  public static float px2dp(Resources resource, float px)  {
    return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}

burada kaynak context.getResources () şeklindedir.


8
Cevap yanlış, çünkü pikselleri dp'ye dönüştürmüyorsunuz - pikselleri piksellere dönüştürüyorsunuz!
Yaroslav

Px2dp yanlış - piksel cinsinden aynı değeri döndürür.
natario

8

bunun gibi:

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

Bağlama bağlı, dönüş float değeri, statik yöntem

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


8

Kotlin'in uzatma fonksiyonunu kullanarak daha zarif bir yaklaşım

/**
 * 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()

Kullanımı:

println("16 dp in pixel: ${16.dpToPx}")
println("16 px in dp: ${16.pxToDp}")

Burada uzantı kullanımını seviyorum. function nameBu durumda fonksiyonları tersine çevirdiğimi "dönüştür " olarak okuyorum . Her işlevin amacını açıklığa kavuşturmak için, işlevlerin adları sırasıyla dpToPx ve pxToDp okumak üzere güncellenebilir.
Maxwell

Resource.getSystem () için dokümanlardan: "Yalnızca sistem kaynaklarına erişim sağlayan (uygulama kaynağı yok) ve geçerli ekran için yapılandırılmamış (boyut birimleri kullanılamıyor, yönlendirme vb.) "
HendraWD

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

2
Bu sadece bu sorunun diğer cevaplarının çoğunda ele alınanla aynı şey değil mi?
TZHX

7

Performans açısından kritik bir uygulama geliştiriyorsanız, lütfen aşağıdaki optimize edilmiş sınıfı göz önünde bulundurun:

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

Sadece sık sık dönüşüm yaparsanız böyle olur. Benim durumumda yaparım.
Pavel

160f nedir? Neden kullanıyorsun, neden 160?
dephinera

160 => 160dpi ve bu formül nedeniyle önlemleri dönüştürmek için
xAqweRx

6

pikselleri dp'ye dönüştürmek için TypedValue kullanın .

Belirtildiği gibi: Dinamik olarak girilmiş veri değeri için kapsayıcı.

ve ApplyDimension yöntemini kullanın :

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

ki bu, bir boyutu tutan paketlenmemiş karmaşık veri değerini aşağıdaki gibi son kayan nokta değerine dönüştürür:

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

Umarım yardımcı olur .


6

Benim için şu şekilde çalışır:

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

Genişlik için de aynısını yapabilirsiniz.



4

Dp'yi pikseller gibi kullanmalısınız. Hepsi bu; bağımsız pikselleri göster. Orta yoğunluklu bir ekranda kullandığınız numaraların aynısını kullanın ve boyut, yüksek yoğunluklu bir ekranda sihirli bir şekilde doğru olacaktır.

Ancak, düzen tasarımınızdaki dolgu_eklemi seçeneğine ihtiyacınız olduğu anlaşılıyor. Görünümünüzün veya denetiminizin üst kapsayıcıda kalan tüm boyutlara genişlemesini istiyorsanız fill_parent kullanın.


aslında benim sorunum benim uygulama yüksek yoğunluklu ekran için kodlanmış ve şimdi düşük yoğunluklu ekrana dönüştürülmesi gerekiyor ..
Indhu

piksellerinizi orta yoğunluklu bir ekran için değiştirin (öykünücüye orta yoğunluklu bir ekran ayarlayabilirsiniz) ve pikseli dp ile değiştirin. Ancak, dolgu_eklemi ve çoklu düzenler kullanılarak daha esnek uygulamalar yapılabilir.
Michael Lowman

Son olarak, manuel olarak dp tüm px değiştirmek için başka bir seçenek yoktu .. :(
Indhu

1
En azından bir dahaki sefere önce dp kullanacaksınız ve hiçbir şeyi değiştirmek zorunda kalmayacaksınız :) Çoğu şey için mutlak konumlandırma gerektirmeyen düzenleri kullanmak mümkün olsa da.
Michael Lowman

İlk uygulamam olduğu için .. bu hatayı yaptım ... bir daha asla yapmayacağım ... :)
Indhu

4

PXve DPfarklı ama benzer.

DPyalnızca ekranın fiziksel boyutunu belirlediğinizde çözünürlüktür. Kullandığınızda DP, düzeninizi farklı pixelyoğunluklara sahip diğer benzer boyutlu ekranlarla ölçeklendirir .

pixelsGerçi bazen istersiniz ve koddaki boyutlarla uğraşırken pixels, dönüştürmediğiniz sürece her zaman gerçekle uğraşıyorsunuz demektir .

Bir robot cihazla normal büyüklükte üzerinde Yani hdpiekranında, 800x480 is 533x320içinde DP(sanırım). Dönüştürmek için DPiçine pixels /1.5geri dönüştürmek için, *1.5. Bu sadece bir ekran boyutu içindir ve dpitasarıma bağlı olarak değişir. Sanatçılarımız bana pixelsyine de veriyor ve DPyukarıdaki 1.5denkleme geçiyorum.


3

Tamsayı değerleri istiyorsanız , Math.round () öğesini kullanmak şamandırayı en yakın tamsayıya yuvarlar.

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

2

Bu benim için çalışıyor (C #):

int pixels = (int)((dp) * Resources.System.DisplayMetrics.Density + 0.5f);

Bu sorunun cevabı değil C # için işe yarıyor. Teşekkürler
Yekmer Şimşek

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
}

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

2

En iyi cevap Android çerçevesinin kendisinden geliyor: sadece bu eşitliği kullanın ...

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

(dp'yi px'e dönüştürür)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.