Konwersja pikseli na dp

826

Stworzyłem swoją aplikację z wysokością i szerokością podaną w pikselach dla urządzenia Pantech, którego rozdzielczość wynosi 480x800.

Muszę przekonwertować wysokość i szerokość dla urządzenia G1.
Myślałem, że konwersja do dp rozwiąże problem i zapewni takie samo rozwiązanie dla obu urządzeń.

Czy jest jakiś prosty sposób na konwersję pikseli na dp?
Jakieś sugestie?

Indhu
źródło
1
Jeśli chcesz zrobić jednorazową konwersję (na przykład w przypadku eksportowania duszków z Photoshopa), oto fajny konwerter .
Paul Lammertsma

Odpowiedzi:

1036
// 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
źródło
331
Uwaga: Powyższe konwertuje DIP na piksele. Pierwotne pytanie dotyczyło konwersji pikseli na dipy!
Eurig Jones
12
Oto prawdziwa odpowiedź na PO: stackoverflow.com/questions/6656540/…
qix
119
To zabawne, że odpowiedź jest bardziej pomocna, gdy tak naprawdę nie odpowiada na pytanie. Myślałem, że chcę tego, o co pytanie, a potem zdałem sobie sprawę, że nie! Świetna odpowiedź. Mam pytanie Jak mogę uzyskać ostatni parametr applyDimension? Czy mogę to zrobić getResource().getDisplayMetrics(), czy jest coś jeszcze?
Andy,
11
UWAGA: stosunkowo droga operacja. Spróbuj buforować wartości, aby uzyskać szybszy dostęp
Entreco
8
Jeśli nie masz dostępu do Contextużycia obiektuResources.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
źródło
8
Być może warto zwrócić wartość int Math.round (px), ponieważ większość metod oczekuje wartości całkowitej
Raj Labana
3
@MuhammadBabar Wynika to z faktu, że 160 dpi (mdpi) jest wartością podstawową, na podstawie której obliczane są inne gęstości. Na przykład hdpi jest uważane za 1,5-krotnie gęstość mdpi, co jest tak naprawdę tylko innym sposobem na powiedzenie 240 dpi. Zobacz odpowiedź Zsolta Safrany poniżej dla wszystkich gęstości.
Stephen
19
@TomTasche: Z dokumentacji dla Resource.getSystem()( wyróżnienie moje): „Zwraca globalny obiekt współdzielonych zasobów, który zapewnia dostęp tylko do zasobów systemowych (bez zasobów aplikacji) i nie jest skonfigurowany dla bieżącego ekranu ( nie może używać jednostek wymiarów , nie zmienia się na podstawie orientacji itp. ”.
Vicky Chijwani,
2
Deweloper ma do wyboru wartość sufitu / podłogi. Lepiej dać kontrolę programistom.
Muhammad Nabeel Arif
7
Chciałbym polecić DisplayMetrics.DENSITY_DEFAULTzamiast 160f developer.android.com/reference/android/util/...
milcaepsilon
285

Najlepiej umieścić w klasie 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
źródło
5
To nie działa na wszystkich urządzeniach! Wynik tej odpowiedzi w porównaniu z wynikiem użycia TypedValue.applyDimension nie jest taki sam w OnePlus 3T (prawdopodobnie dlatego, że OnePlus ma wbudowane niestandardowe skalowanie w systemie operacyjnym). Użycie TypedValue.applyDimension powoduje spójne zachowanie na różnych urządzeniach.
Ben De La Haye,
196
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;

density równa się

  • .75włączony ldpi( 120dpi)
  • 1.0włączony mdpi( 160dpi; linia bazowa)
  • 1.5włączony hdpi( 240dpi)
  • 2.0włączony xhdpi( 320dpi)
  • 3.0włączony xxhdpi( 480dpi)
  • 4.0włączony xxxhdpi( 640dpi)

Użyj tego konwertera online do zabawy z wartościami dpi.

EDYCJA: Wydaje się, że nie ma związku 1: 1 między dpiwiadrem a density. Wygląda na to, że Nexus 5Xistota xxhdpima densitywartość 2.625(zamiast 3). Przekonaj się w Metryk urządzenia .

Zsolt Safrany
źródło
3
„Wygląda na to, że Nexus 5X będący xxhdpi ma gęstość 2,6 (zamiast 3)” - Technicznie Nexus 5X ma 420dpi, a Nexus 6 / 6P ma 560dpi, żaden nie ląduje bezpośrednio w jednym ze standardowych wiader, tak jak Nexus 7 z tvdpi (213dpi). Więc strona wymieniająca je jako xxdpi i xxxhdpi to farsa. Twój wykres jest poprawny, a urządzenia te odpowiednio skalują w oparciu o swoje „specjalne” przedziały dpi.
Steven Byle
108

Możesz użyć tego .. bez kontekstu

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

Jak wspomniano w @Stan ... stosowanie tego podejścia może powodować problemy, jeśli system zmieni gęstość. Więc bądź tego świadomy!

Osobiście używam do tego kontekstu. To tylko kolejne podejście, którym chciałem się z tobą podzielić

Maher Abuthraa
źródło
11
Możesz nie chcieć tego używać. Dokumentacja dla getSystem () - „Zwraca globalny obiekt współdzielonych zasobów, który zapewnia dostęp tylko do zasobów systemowych (bez zasobów aplikacji) i nie jest skonfigurowany dla bieżącego ekranu (nie może używać jednostek wymiarów, nie zmienia się w zależności od orientacji itp.) . ”
Stan
Opieranie się na tym, co mówi @Stan: jest to niebezpieczne i nie powinieneś go używać, szczególnie teraz, gdy czynniki kształtujące urządzenia stają się tak złożone.
Saket,
93

Jeśli możesz użyć wymiarów XML, jest to bardzo proste!

W twoim res/values/dimens.xml:

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

Następnie w Javie:

getResources().getDimensionPixelSize(R.dimen.thumbnail_height);
Alex
źródło
Ponieważ px do dp zależy od gęstości ekranu, nie wiem, w jaki sposób OP uzyskał 120, chyba że testował metodę px do dp na wszystkich różnych rozmiarach ekranu.
John61590,
75

Zgodnie z Android Development Guide:

px = dp * (dpi / 160)

Ale często będziesz chciał to zrobić odwrotnie, gdy otrzymasz projekt wyrażony w pikselach. Więc:

dp = px / (dpi / 160)

Jeśli korzystasz z urządzenia o rozdzielczości 240dpi, współczynnik ten wynosi 1,5 (jak podano wcześniej), więc oznacza to, że ikona 60px jest równa 40dp w aplikacji.

Ricardo Magalhães
źródło
7
160 jest stała, odpowiedź łóżka
25
2
@ user25 Właściwie świetna odpowiedź. Nie czytałeś żadnych dokumentów na ekranach Androida? 160 jest powszechną stałą w każdym miejscu, gdy mówi się o gęstości ekranu Androida. Cytat z dokumentów: „ekrany o średniej gęstości (mdpi) (~ 160dpi). (To jest gęstość linii podstawowej)”. Chodź, człowieku
mykolaj
70

Bez Contexteleganckich metod statycznych:

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
źródło
24
Resources.getSystem()javadoc mówi: „Zwraca globalny obiekt współdzielonych zasobów, który zapewnia dostęp tylko do zasobów systemowych (bez zasobów aplikacji) i nie jest skonfigurowany dla bieżącego ekranu (nie może używać jednostek wymiarów, nie zmienia się w zależności od orientacji itp.”). To prawie mówi, że nie powinieneś tego robić, nawet jeśli jakoś to działa.
Austyn Mahoney
Właśnie przeczytałem komentarz @ AustynMahoney i zdałem sobie sprawę, że ta odpowiedź nie jest tak świetna, jak początkowo myślałem, ale SO nie pozwoli mi cofnąć mojego poparcia ! Argh!
Vicky Chijwani,
45

Dla DP to Pixel

Utwórz wartość w dimens.xml

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

Uzyskaj tę wartość pixeljako:

int sizeInPixel = context.getResources().getDimensionPixelSize(R.dimen.textSize);
asadnwfp
źródło
39

Możesz zatem użyć następującego formulatora, aby obliczyć odpowiednią liczbę pikseli na podstawie wymiaru określonego w 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
źródło
4
Konwertuje to dp na piksele, ale wywołałeś metodę convertToDp.
Qwertie,
4
+ 0,5f wyjaśniono tutaj -> developer.android.com/guide/practices/… . Służy do zaokrąglania w górę do najbliższej liczby całkowitej.
Bae,
jedyna poprawna odpowiedź. możesz dodać źródło developer.android.com/guide/practices/…
user25
web.archive.org/web/20140808234241/http://developer.android.com/… w przypadku linku, który nadal zawiera kwestionowaną treść
caw
39

Dla każdego, kto używa Kotlin:

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

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

Stosowanie:

64.toPx
32.toDp
Gunhan
źródło
Z dokumentacji dotyczącej Resource.getSystem (): „Zwraca globalny obiekt zasobów współdzielonych, który zapewnia dostęp tylko do zasobów systemowych (bez zasobów aplikacji) i nie jest skonfigurowany dla bieżącego ekranu (nie może używać jednostek wymiarów, nie zmienia się w zależności od orientacja itp. ”.
HendraWD
@HendraWD Dokumenty mogą być mylące, o których wspomina, że ​​jednostki wymiarów na poziomie aplikacji zmniejszają zasoby. displayMetrics nie jest zasobem na poziomie aplikacji. Jest zasobem systemowym i zwraca prawidłowe wartości. Ten kod działa poprawnie we wszystkich moich aplikacjach Prod. Nigdy nie miałem problemu.
Gunhan
33

Domyślne użycie w zestawie Android SDK: http://developer.android.com/reference/android/util/TypedValue.html

float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
Kvant
źródło
Powinieneś używać tego. Jako bonus zrobi również SP.
Mark Renouf
2
resultPixpowinien być typu int. int resultPix = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
vovahost
27

użycie rozszerzenia kotlin czyni go lepszym

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

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

AKTUALIZACJA:

Ponieważ displayMetricsjest częścią globalnych zasobów współdzielonych , możemy z nich korzystaćResources.getSystem()

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

fun Int.toDp(): Int = (this / Resources.getSystem().displayMetrics.density).toInt()
Beigirad
źródło
4
Po co dodawać go jako rozszerzenie Int, odpowiedzialność nie musi nic robić z typem Int.
htafoya
19

To powinno dać ci konwersję dp na piksele:

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

To powinno dać ci konwersję pikseli do dp:

public static int pxToDp(int px)
{
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
Wojna Venki
źródło
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
źródło
12

Prawdopodobnie najlepszym sposobem, jeśli masz wymiar wewnątrz wartości / dimen, jest uzyskanie wymiaru bezpośrednio z metody getDimension (), zwróci ci on wymiar już przekonwertowany na wartość w pikselach.

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

Żeby to lepiej wyjaśnić,

getDimension(int resourceId) 

zwróci wymiar już przekonwertowany na piksel AS A FLOAT.

getDimensionPixelSize(int resourceId)

zwróci to samo, ale obcięte do int, więc JAKO INTEGR.

Zobacz dokumentację Androida

Lorenzo Barbagli
źródło
9
Aby przekonwertować dp na piksele.
public static int dp2px(Resources resource, int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,   dp,resource.getDisplayMetrics());
}
Aby przekonwertować piksel na dp.
  public static float px2dp(Resources resource, float px)  {
    return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}

gdzie zasób to context.getResources ().

Książę Gupta
źródło
8
Odpowiedź jest zła, ponieważ nie konwertujesz pikseli na dp - konwertujesz piksele na piksele!
Jarosław
Px2dp jest nieprawidłowy - zwraca tę samą wartość w pikselach.
natario
8

lubię to:

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

zależy od kontekstu, zwraca wartość zmiennoprzecinkową, metodę statyczną

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

Trinea
źródło
8

Bardziej eleganckie podejście dzięki funkcji przedłużania 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()

Stosowanie:

println("16 dp in pixel: ${16.dpToPx}")
println("16 px in dp: ${16.pxToDp}")
Saeed Masoumi
źródło
Uwielbiam korzystanie z rozszerzenia tutaj. Czytam funkcje jako „przekonwertuj na function name”, co, jak zdaję sobie sprawę, jest w tym przypadku odwrócone. Aby wyjaśnić zamiary każdej funkcji, nazwy funkcji można zaktualizować tak, aby odczytały odpowiednio dpToPx i pxToDp.
Maxwell
Z dokumentacji dotyczącej Resource.getSystem (): „Zwraca globalny obiekt zasobów współdzielonych, który zapewnia dostęp tylko do zasobów systemowych (bez zasobów aplikacji) i nie jest skonfigurowany dla bieżącego ekranu (nie może używać jednostek wymiarów, nie zmienia się w zależności od orientacja itp. ”.
HendraWD
7
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);
Sibin
źródło
2
Czy to nie tylko to samo, co ujęte w wielu innych odpowiedziach na to pytanie?
TZHX
7

Jeśli opracowujesz aplikację krytyczną dla wydajności, rozważ następującą zoptymalizowaną klasę:

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
źródło
To sprawia, że ​​tylko wtedy, gdy wykonujesz konwersje naprawdę często. W moim przypadku tak.
Pavel
Co to jest 160f? Dlaczego go używasz, dlaczego jest to 160?
dephinera,
160 => 160dpi, a to jest do konwersji miar ze względu na formułę
xAqweRx
6

do konwersji pikseli na dp użyj TypedValue .

Jak wspomniano w dokumentacji: Kontener na dynamicznie wpisywaną wartość danych.

i użyj metody applyDimension :

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

który konwertuje rozpakowaną złożoną wartość danych zawierającą wymiar na końcową wartość zmiennoprzecinkową, jak poniżej:

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

Mam nadzieję, że to pomaga.


źródło
6

Tak to dla mnie działa:

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

Możesz zrobić to samo dla szerokości.

Temi Mide Adey
źródło
4

Powinieneś używać dp tak samo jak pikseli. To wszystko, czym są; wyświetlać niezależne piksele. Użyj tych samych liczb, które byłyby na ekranie o średniej gęstości, a rozmiar będzie magicznie poprawny na ekranie o wysokiej gęstości.

Wygląda jednak na to, że potrzebna jest opcja fill_parent w projekcie układu. Użyj fill_parent, jeśli chcesz, aby widok lub kontrolka rozszerzyły się na cały pozostały rozmiar w kontenerze nadrzędnym.

Michael Lowman
źródło
w rzeczywistości moim problemem jest to, że moja aplikacja jest zakodowana dla ekranu o wysokiej gęstości i teraz musi zostać przekonwertowana na ekran o niskiej gęstości.
Indhu
zmodyfikuj swoje piksele dla ekranu średniej gęstości (możesz ustawić ekran średniej gęstości w emulatorze) i zastąp piksel dp. Można jednak tworzyć bardziej elastyczne aplikacje przy użyciu fill_parent i wielu układów.
Michael Lowman,
W końcu nie miałem innej opcji, jak ręcznie zmienić wszystkie
piksele
1
Przynajmniej następnym razem użyjesz dp i nie będziesz musiał niczego zmieniać :) Chociaż powinno być możliwe użycie układów, które nie wymagają absolutnego pozycjonowania dla większości rzeczy.
Michael Lowman,
Ponieważ była to moja pierwsza aplikacja .. popełniłem ten błąd ... nigdy więcej tego nie zrobię ... :)
Indhu
4

PXi DPsą różne, ale podobne.

DPto rozdzielczość, gdy uwzględnisz tylko fizyczny rozmiar ekranu. Gdy DPgo użyjesz , przeskalujesz swój układ do innych ekranów o podobnych rozmiarach i różnej pixelgęstości.

Czasami jednak tak naprawdę chcesz pixels, a kiedy zajmujesz się wymiarami w kodzie, zawsze masz do czynienia z rzeczywistymi pixels, chyba że je przekonwertujesz.

Tak więc na urządzeniu z Androidem, normalnym hdpiekranie, 800x480 is 533x320w DP(wierzę). Aby przekonwertować DPna pixels /1.5, przekonwertować z powrotem *1.5. Dotyczy to tylko jednego rozmiaru ekranu i dpizmieniałby się w zależności od projektu. Nasi artyści dają mi pixelsjednak i przechodzę do DPpowyższego 1.5równania.

HaMMeReD
źródło
3

Jeśli chcesz uzyskać wartości całkowite , to użycie Math.round () zaokrągli liczbę zmiennoprzecinkową do najbliższej liczby całkowitej.

public static int pxFromDp(final float dp) {
        return Math.round(dp * Resources.getSystem().getDisplayMetrics().density);
    }
Hitesh Sahu
źródło
2

To działa dla mnie (C #):

int pixels = (int)((dp) * Resources.System.DisplayMetrics.Density + 0.5f);
Michael Zhang
źródło
Nie jest to odpowiedź na to pytanie, ale działa w C #. Dzięki
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
źródło
2

Najlepsza odpowiedź pochodzi z samego systemu Android: użyj tej równości ...

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

(konwertuje dp na px)

JarsOfJam-Scheduler
źródło