Перетворення пікселів у dp


826

Я створив свою програму з висотою та шириною, вказаною в пікселях для пристрою Pantech, роздільною здатністю якого є 480x800.

Мені потрібно перетворити висоту і ширину для пристрою G1.
Я думав, що перетворення його на dp вирішить проблему та забезпечить однакове рішення для обох пристроїв.

Чи є якийсь простий спосіб перетворити пікселі в dp?
Будь-які пропозиції?


1
Якщо ви хочете зробити одноразове перетворення (наприклад, для експорту спрайтів з Photoshop), ось прекрасний конвертер .
Пол Ламмерцма


Відповіді:


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
Примітка. Вищенаведене - це перетворення DIP в пікселі. Оригінальне запитання задавало, як перетворити пікселі в Dips!
Евриг Джонс

12
Ось реальна відповідь на OP: stackoverflow.com/questions/6656540 / ...
Qix

119
Смішно, як відповідь корисніша, коли вона насправді не відповідає на питання -_- Я думала, що хочу те, що запитував, тоді зрозуміла, що цього не роблю! Так чудова відповідь. У мене є питання. Як я можу отримати останній параметр для applyDimension? Чи можу я просто зробити getResource().getDisplayMetrics(), чи є щось інше?
Енді

11
ПРИМІТКА: відносно дорога операція. Спробуйте кешувати значення для швидшого доступу
Entreco

8
Якщо ви не маєте доступу до Contextвикористання об’єктівResources.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
Можливо, варто повернути int Math.round (px), оскільки більшість методів очікують ціле значення
Радж Лабана

3
@MuhammadBabar Це тому, що 160 точок на дюйм (mdpi) є базовим значенням, з якого обчислюються інші щільності. Наприклад, hdpi вважається 1,5-кратною щільністю mdpi, що насправді є лише іншим способом сказати 240 dpi. Дивіться відповідь Золта Сафрани нижче про всі щільності.
Стівен

19
@TomTasche: З Документів для Resource.getSystem()(міна акценту): "Повернути глобальний об'єкт спільних ресурсів, який забезпечує доступ лише до системних ресурсів (без ресурсів програми), і не налаштований для поточного екрана ( не може використовувати одиниці виміру , не змінюється на основі орієнтації тощо). "
Vicky Chijwani

2
Забудовники мають вибір на висоту стель / підлоги. Краще дати контроль розробнику.
Мухаммад Набіл Аріф

7
Я б рекомендував DisplayMetrics.DENSITY_DEFAULTзамість 160f developer.android.com/reference/android/util/…
milcaepsilon

285

Переважно ставити в клас 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
Це працює не на всіх пристроях! Результат цієї відповіді проти використання TypedValue.applyDimension не однаковий на OnePlus 3T (можливо, тому, що OnePlus має вбудовані в ОС спеціальні масштаби). Використання TypedValue.applyDimension викликає послідовну поведінку на всіх пристроях.
Бен Де Ла Хей

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

density дорівнює

  • .75увімкнено ldpi( 120dpi)
  • 1.0on mdpi( 160dpi; базовий рівень)
  • 1.5увімкнено hdpi( 240dpi)
  • 2.0увімкнено xhdpi( 320dpi)
  • 3.0увімкнено xxhdpi( 480dpi)
  • 4.0увімкнено xxxhdpi( 640dpi)

Використовуйте цей онлайн-конвертер, щоб пограти зі значеннями dpi.

EDIT: Здається, що між dpiвідром та ковбасом немає відносин 1: 1 density. Схоже, Nexus 5Xістота xxhdpiмає densityзначення 2.625(замість 3). Переконайтеся самі в метриці пристроїв .


3
"Схоже, що Nexus 5X, що має xxhdpi, має значення щільності 2,6 (замість 3)". - Технічно Nexus 5X становить 420dpi, а Nexus 6 / 6P - 560dpi, і не приземляється безпосередньо в одному зі стандартних відра, як і Nexus 7 з tvdpi (213dpi). Тож сайт із переліком таких як xxdpi та xxxhdpi - це фарс. Ваша діаграма є правильною, і ці пристрої належним чином масштабуватимуть одне «спеціальне» відро для dpi.
Стівен Біле

108

Ви можете використовувати це .. без контексту

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 .. використання цього підходу може спричинити проблеми, якщо система змінює щільність. Тож пам’ятайте про це!

Особисто я використовую Context для цього. Я просто хотів поділитися з вами


11
Можливо, ви не хочете цим користуватися. Документація для getSystem () - "Повернення глобального об'єкта спільних ресурсів, який забезпечує доступ лише до системних ресурсів (без ресурсів програми) та не налаштований для поточного екрану (не може використовувати одиниці вимірів, не змінюється на основі орієнтації тощо) . "
Стен

Оголошення того, що говорить @Stan: це небезпечно, і ви не повинні його використовувати, особливо зараз, коли фактори форми пристрою стають настільки складними.
Сакет

93

Якщо ви можете використовувати розміри XML, це дуже просто!

У вашому res/values/dimens.xml:

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

Потім у вашій Java:

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

Оскільки px to dp залежить від щільності екрана, я не знаю, як ОП отримала 120 в першу чергу, якщо тільки він не перевірив метод px to dp для всіх різних розмірів екрана.
John61590

75

Відповідно до посібника з розробки Android:

px = dp * (dpi / 160)

Але часто вам потрібно виконати це навпаки, коли отримаєте дизайн, зазначений у пікселях. Тому:

dp = px / (dpi / 160)

Якщо ви перебуваєте на пристрої 240dpi, це співвідношення становить 1,5 (як це було зазначено раніше), тому це означає, що піктограма 60px дорівнює 40dp у додатку.



7
160 постійна, відповідь ліжка
користувач25

2
@ user25 Насправді чудова відповідь. Ви не читали жодних документів на екранах Android? 160 - загальна константа в усьому світі, коли ми говоримо про щільність екрану для Android. Цитата з docs: "екрани середньої щільності (mdpi) (~ 160dpi). (Це щільність базової лінії)". Давай, людина
Миколай

70

Без Contextелегантних статичних методів:

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 каже: "Поверніть глобальний об'єкт спільних ресурсів, який забезпечує доступ лише до системних ресурсів (без ресурсів програми) та не налаштований для поточного екрану (не можна використовувати одиниці виміру, не змінюється на основі орієнтації тощо". Це майже говорить, що ви не повинні цього робити, навіть якщо це якось працює.
Austyn Mahoney

Я просто прочитав коментар @ AustynMahoney і зрозумів, що ця відповідь не така велика, як я спочатку думав, але ТАК не дозволить мені скасувати свою пропозицію ! Арг!
Vicky Chijwani

45

Для DP to Pixel

Створіть значення в dimens.xml

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

Отримайте це значення у pixelвигляді:

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

39

Отже, ви можете використовувати наступний формуляр для обчислення потрібної кількості пікселів із розмірності, зазначеної в 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
Це перетворює dp у пікселі, але ви назвали свій метод convertToDp.
Qwertie

4
+ 0,5f поясніть тут -> developer.android.com/guide/practices/… . Він використовується для округлення до найближчого цілого числа.
Bae

єдина правильна відповідь. Ви можете додати джерело developer.android.com/guide/practices/…
користувач25

web.archive.org/web/20140808234241/http://developer.android.com/… за посиланням, яке все ще містить відповідний вміст
caw

39

Для всіх, хто використовує Kotlin:

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

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

Використання:

64.toPx
32.toDp

З документів для Resource.getSystem (): "Повернути глобальний об'єкт спільних ресурсів, який забезпечує доступ лише до системних ресурсів (без ресурсів програми) та не налаштований для поточного екрану (не може використовувати одиниці виміру, не змінюється на основі орієнтація тощо). "
HendraWD

@HendraWD Документи можуть заплутатися, одиниці розмірів, про які вона згадує, - це ваш рівень програми, що зменшує ресурси. displayMetrics не є ресурсом рівня програми. Це системний ресурс і він повертає правильні значення. Цей код чудово працює у всіх моїх програмах Prod. Ніколи не було проблем.
Гунхань

33

У програмі SDK для Android існує утиліта за замовчуванням: http://developer.android.com/reference/android/util/TypedValue.html

float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())

Ви повинні використовувати цей. Як бонус він також зробить SP.
Марк Ренуф

2
resultPixмає бути типу int. int resultPix = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
vovahost

27

використання розширення kotlin робить його кращим

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

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

ОНОВЛЕННЯ:

Через те, що displayMetricsє частиною глобальних спільних ресурсів , ми можемо використовуватиResources.getSystem()

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

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

4
Чому б ви додали його як розширення Int, відповідальність не повинна нічого робити з типом Int.
хтафоя

19

Це повинно дати вам перетворення dp у пікселі:

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

Це має дати вам пікселі конверсії в dp:

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

19

Котлін

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

Мабуть, найкращий спосіб, якщо у вас є розмір всередині значень / dimen - отримати розмірність безпосередньо методом getDimension (), він поверне вам параметр, вже перетворений у значення пікселя.

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

Просто, щоб краще пояснити це,

getDimension(int resourceId) 

поверне розмір, вже перетворений у піксель AS AS FLOAT.

getDimensionPixelSize(int resourceId)

поверне той самий, але усічений до int, так ЯКІЙ ІНТЕГРІЙ.

Див. Посилання на Android


9
Для перетворення dp в піксель.
public static int dp2px(Resources resource, int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,   dp,resource.getDisplayMetrics());
}
Для перетворення пікселів у dp.
  public static float px2dp(Resources resource, float px)  {
    return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}

де ресурсом є контекст.getResources ().


8
Відповідь неправильна, тому що ви не перетворюєте пікселі в dp - ви перетворюєте пікселі в пікселі!
Ярослав

Px2dp неправильний - поверне те саме значення в пікселях.
Натаріо

8

подобається це:

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

залежно від контексту, зворотного поплавкового значення, статичного методу

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


8

Більш елегантний підхід із використанням функції розширення 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()

Використання:

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

Тут дуже подобається використання розширення. Я читаю функції як "перетворити на function name", що я розумію, що в цьому випадку є зворотним. Щоб уточнити наміри кожної функції, імена функцій можуть бути оновлені до зчитування відповідно dpToPx та pxToDp.
Максвелл

З документів для Resource.getSystem (): "Повернути глобальний об'єкт спільних ресурсів, який забезпечує доступ лише до системних ресурсів (без ресурсів програми) та не налаштований для поточного екрану (не може використовувати одиниці виміру, не змінюється на основі орієнтація тощо). "
HendraWD

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

2
Чи це не те саме, що описано в багатьох інших відповідях на це питання?
TZHX

7

Якщо ви розробляєте критичну програму для роботи, врахуйте наступний оптимізований клас:

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

Це робить сенс лише у тому випадку, якщо ви робите конверсії дуже часто. У моєму випадку я це роблю.
Павло

Що таке 160f? Для чого ви його використовуєте, чому це 160?
дефінера

160 => 160dpi, і це для перетворення заходів через формулу
xAqweRx

6

для перетворення пікселів у dp використовуйте TypedValue .

Як зазначено в документації: Контейнер для динамічно набраного значення даних.

і використовувати метод applyDimension :

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

який перетворює розпаковане комплексне значення даних, що містить розмір, у його кінцеве значення з плаваючою комою, наприклад:

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

Сподіваюся, що допомагає.


6

Ось як це працює для мене:

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

Можна зробити те ж саме для ширини.



4

Ви повинні використовувати dp так само, як і пікселі. Це все, що вони є; відображення незалежних пікселів. Використовуйте ті самі цифри, що і на екрані середньої щільності, і розмір буде магічно правильним на екрані з високою щільністю.

Однак це виглядає як те, що вам потрібно - варіант fill_parent в дизайні вашого макета. Використовуйте fill_parent, коли ви хочете, щоб ваш перегляд або елемент керування розширилися на весь розмір, що залишився в батьківському контейнері.


насправді моя проблема полягає в тому, що моя програма кодується для екрану з високою щільністю, і тепер її потрібно перетворити на екран низької щільності ..
Indhu

змінити пікселі для екрана середньої щільності (ви можете встановити екран середньої щільності в емуляторі) та замінити піксель на dp. Однак більш гнучкі програми можна зробити, використовуючи fill_parent та декілька макетів.
Майкл Лоуман

Нарешті, у мене не було іншого варіанту, як змінити всі px на dp вручну .. :(
Indhu

1
Принаймні наступного разу, коли ви спочатку скористаєтеся dp і нічого не потрібно буде змінювати :) Хоча слід використовувати можливість макетів, які не потребують абсолютного позиціонування для більшості речей.
Майкл Лоуман

Оскільки це був мій перший додаток .. я зробив цю помилку ... я більше ніколи цього не зроблю ... :)
Indhu

4

PXі DPрізні, але схожі.

DP- це роздільна здатність, коли ви враховуєте лише фізичний розмір екрана. Під час використання DPвін буде масштабувати ваш макет на інших аналогічних за розміром екранах з різною pixelщільністю.

Іноді ви насправді хочете pixels, і коли ви маєте справу з розмірами в коді, ви завжди маєте справу з реальними pixels, якщо не перетворюєте їх.

Так що на андроїд-пристрої, звичайного розміру hdpiекрана, 800x480 is 533x320в DP(я вважаю). Перетворити DPв pixels /1.5, перетворити назад *1.5. Це лише для одного розміру екрана, і dpiвін мінятиметься залежно від дизайну. Наші артисти дають мені, pixelsхоча я перетворююсь на DPвищезгадане 1.5рівняння.


3

Якщо ви хочете значення Integer, то за допомогою Math.round () буде округлий поплавок до найближчого цілого числа.

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

2

Це працює для мене (C #):

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

Не відповідь на це питання, але для C # це працює. Спасибі
Yekmer Simsek

2

котлін

   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

Найкраща відповідь виходить із самої системи Android: просто використовуйте цю рівність ...

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

(перетворює dp в px)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.