Преобразование пикселей в дп

827

Я создал свое приложение с высотой и шириной в пикселях для устройства Pantech с разрешением 480x800.

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

Есть ли простой способ конвертировать пиксели в dp?
Какие-либо предложения?

Indhu
источник
1
Если вы хотите выполнить однократное преобразование (например, для экспорта спрайтов из Photoshop), вот отличный конвертер .
Пол Ламмерцма

Ответы:

1038
// 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
источник
333
Примечание. Выше приведено преобразование DIP в пиксели. Оригинальный вопрос спрашивал, как конвертировать пиксели в Dips!
Эуриг Джонс
12
Вот реальный ответ для OP: stackoverflow.com/questions/6656540/…
qix 7
120
Забавно, что ответ более полезен, когда он на самом деле не отвечает на вопрос -_- Я подумал, что хочу то, что задал вопрос, и понял, что нет! Отличный ответ. У меня есть вопрос. Как я могу получить последний параметр для applyDimension? Могу ли я просто сделать getResource().getDisplayMetrics(), или есть что-то еще?
Энди
11
ПРИМЕЧАНИЕ: относительно дорогая операция. Попробуйте кэшировать значения для более быстрого
доступа
8
Если у вас нет доступа к ContextобъектамResources.getSystem().getDisplayMetrics()
Фаршад Тахмасби
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 dpi (mdpi) - это базовое значение, из которого рассчитываются другие плотности. Например, hdpi, как полагают, в 1.5 раза больше плотности mdpi, что на самом деле является еще одним способом сказать 240 dpi. См. Ответ Жолта Сафрани ниже для всех плотностей.
Стивен
19
@TomTasche: Из документов для Resource.getSystem()(выделено мной): "Возвращать глобальный объект общих ресурсов, который обеспечивает доступ только к системным ресурсам (без ресурсов приложения) и не настроен для текущего экрана ( не может использовать единицы измерения , не изменяется на основе ориентации и т. д.)
Вики Чиджвани
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 вызывает согласованное поведение на всех устройствах.
Бен Де Ла Хэй
197
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;

density равно

  • .75на ldpi( 120точек на дюйм)
  • 1.0на mdpi( 160т / д; базовый уровень)
  • 1.5на hdpi( 240точек на дюйм)
  • 2.0на xhdpi( 320точек на дюйм)
  • 3.0на xxhdpi( 480точек на дюйм)
  • 4.0на xxxhdpi( 640точек на дюйм)

Используйте этот онлайн-конвертер, чтобы поиграться со значениями точек на дюйм.

РЕДАКТИРОВАТЬ: Кажется, нет никакого отношения 1: 1 между dpiведром и density. Похоже, что Nexus 5Xсущество xxhdpiимеет densityзначение 2.625(а не 3). Убедитесь сами в метриках устройства .

Жолт Сафраны
источник
3
«Похоже, что Nexus 5X, будучи xxhdpi, имеет значение плотности 2,6 (вместо 3)» - Технически Nexus 5X имеет 420 точек на дюйм, а Nexus 6 / 6P имеет 560 точек на дюйм, и не попадает непосредственно в одно из стандартных сегментов, как Nexus 7 с ТВДПИ (213dpi). Таким образом, сайт, на котором перечислены такие как xxdpi и xxxhdpi, является фарсом. Ваша диаграмма верна, и эти устройства будут правильно масштабироваться на основе их «специальных» точек на дюйм.
Стивен Байл
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 .. использование этого подхода может вызвать проблемы, если система изменит плотность. Так что знайте об этом!

Лично я использую контекст, чтобы сделать это. Это просто еще один подход, которым я хотел бы поделиться с вами

Махер Абутраа
источник
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);
Alex
источник
Поскольку размер пикселя в пиксель зависит от плотности экрана, я не знаю, каким образом ОП получил 120, если только он или она не проверил метод пикселя в пиксель на всех экранах разных размеров.
John61590
75

Согласно Руководству по разработке Android:

px = dp * (dpi / 160)

Но часто вам захочется выполнить это наоборот, когда вы получите дизайн, который указан в пикселях. Так:

dp = px / (dpi / 160)

Если вы используете устройство с разрешением 240 точек на дюйм, это соотношение равно 1,5 (как указано выше), поэтому это означает, что значок 60px в приложении равен 40dp.

Рикардо Магальес
источник
2
Indhu, Вы можете обратиться сюда developer.android.com/guide/practices/… и developer.android.com/reference/android/util/…
Саччидан и
7
160 постоянно, постельный ответ
user25
2
@ user25 Отличный ответ на самом деле. Разве вы не читали какие-либо документы на экранах Android? 160 - это общая константа, когда речь идет о плотности экрана Android. Цитата из документа: «Экраны средней плотности (мдпи) (~ 160 точек на дюйм). (Это базовая плотность)». Давай, парень
Николай
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 говорится: «Возвращать глобальный объект общих ресурсов, который обеспечивает доступ только к системным ресурсам (без ресурсов приложения) и не настроен для текущего экрана (не может использовать единицы измерения, не изменяется в зависимости от ориентации и т. д.)». Это в значительной степени говорит о том, что вы не должны делать это, даже если это как-то работает.
Остин Махони
Я только что прочитал комментарий @ AustynMahoney и понял, что этот ответ не так хорош, как я первоначально думал, но ТАК не позволит мне отменить мое возражение ! Argh!
Вики Чиджвани
45

За DP to Pixel

Создать значение в dimens.xml

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

Получите это значение pixelкак:

int sizeInPixel = context.getResources().getDimensionPixelSize(R.dimen.textSize);
asadnwfp
источник
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);
}
Neeraj T
источник
4
Это преобразует дп в пиксели, но вы вызвали свой метод convertToDp.
Qwertie
4
+ 0.5f это объяснить здесь -> developer.android.com/guide/practices/… . Используется для округления до ближайшего целого числа.
Bae
единственный правильный ответ. Вы можете добавить источник developer.android.com/guide/practices/...
user25
web.archive.org/web/20140808234241/http://developer.android.com/... для связи , которая до сих пор имеет содержание вопроса
каркать
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
Gunhan
источник
Из документов для Resource.getSystem (): «Вернуть глобальный объект общих ресурсов, который предоставляет доступ только к системным ресурсам (без ресурсов приложения) и не настроен для текущего экрана (не может использовать единицы измерения, не изменяется на основе ориентация и т. д.)
HendraWD
@HendraWD Документы могут сбивать с толку, единицы измерения, о которых идет речь, - это ресурсы вашего уровня, измеряющие ресурсы. displayMetrics не является ресурсом уровня приложения. Это системный ресурс, и он возвращает правильные значения. Этот код отлично работает на всех моих приложениях Prod. Никогда не было проблемы.
Ганхан
33

В Android SDK есть утилита по умолчанию: 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-extension делает его лучше

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()
beigirad
источник
4
Зачем вам добавлять его как расширение Int, ответственность не имеет ничего общего с типом Int.
Хтафоя
19

Это должно дать вам преобразование дп в пиксели:

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);
}
Venki WAR
источник
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)
}

Ява

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
источник
12

Вероятно, лучший способ, если у вас есть измерение внутри values ​​/ измерение, это получить измерение непосредственно из метода getDimension (), он вернет вам измерение, уже преобразованное в значение в пикселях.

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

Просто чтобы лучше объяснить это,

getDimension(int resourceId) 

вернет размер, уже преобразованный в пиксель как плавающий элемент.

getDimensionPixelSize(int resourceId)

вернет то же самое, но усеченное до int, так что как INTEGER.

См. Справочник по Android

Лоренцо Барбальи
источник
9
Чтобы преобразовать дп в пиксель.
public static int dp2px(Resources resource, int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,   dp,resource.getDisplayMetrics());
}
Чтобы преобразовать пиксель в дп.
  public static float px2dp(Resources resource, float px)  {
    return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}

где ресурс это context.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

Trinea
источник
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);
Sibin
источник
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?
Dephinera
160 => 160
точек на дюйм,
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

Если вы хотите целочисленные значения, то использование Math.round () округляет число с плавающей точкой до ближайшего целого числа.

public static int pxFromDp(final float dp) {
        return Math.round(dp * Resources.getSystem().getDisplayMetrics().density);
    }
Хите саху
источник
3

Лучший ответ исходит от самой платформы 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)

JarsOfJam-планировщик
источник
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
}

Ява

   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;
}
Юнес
источник