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.