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?


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

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

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

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 .


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ć


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

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.



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

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

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

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

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


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

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

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

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


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


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


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

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

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

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.


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.



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.


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.


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

2

To działa dla mnie (C #):

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

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

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)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.