Формула px для dp, dp для px android

Я пытаюсь вычислить переменное количество пикселей на независимые от плотности пиксели и наоборот.

Эта формула (px to dp): dp = (int)(px / (displayMetrics.densityDpi / 160)); не работает на небольших устройствах, потому что она делится на ноль.

Это моя формула dp to px:

px = (int)(dp * (displayMetrics.densityDpi / 160));

Может ли кто-нибудь дать мне несколько указателей?

Ответы

Ответ 1

Примечание. Широко используемое выше решение основано на displayMetrics.density. Однако в документах объясняется, что это значение представляет собой округленное значение, используемое с экранными "ведрами". Например. на моем Nexus 10 он возвращает 2, где реальное значение будет 298dpi (real)/160dpi (по умолчанию) = 1.8625.

В зависимости от ваших требований вам может потребоваться точная трансформация, которая может быть достигнута следующим образом:

[Edit] Это не должно смешиваться с внутренним dp-блоком Android, так как это, конечно, по-прежнему основано на ведрах экрана. Используйте это, когда вы хотите, чтобы устройство отображало один и тот же реальный размер на разных устройствах.

Преобразование dp в пиксель:

public int dpToPx(int dp) {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));     
}

Преобразование пикселя в dp:

public int pxToDp(int px) {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}

Обратите внимание, что есть свойства xdpi и ydpi, вы можете выделить их, но я не могу представить себе разумный дисплей, где эти значения сильно отличаются.

Ответ 2

Я решил свою проблему, используя следующие формулы. Пусть другие люди извлекут выгоду из этого.

dp to px:

displayMetrics = context.getResources().getDisplayMetrics();
return (int)((dp * displayMetrics.density) + 0.5);

px для dp:

displayMetrics = context.getResources().getDisplayMetrics();
return (int) ((px/displayMetrics.density)+0.5);

Ответ 3

px для dp:

int valueInpx = ...;
int valueInDp= (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, valueInpx , getResources()
                .getDisplayMetrics());

Ответ 4

Просто вызовите getResources().getDimensionPixelSize(R.dimen.your_dimension) для преобразования из dp единиц в пиксели

Ответ 5

Эффективный способ когда-либо

DP для пикселя:

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

Пиксель для DP:

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

Надеюсь, это поможет вам.

Ответ 6

Использовать эту функцию

private int dp2px(int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}

Ответ 7

px = dp * (dpi / 160)

dp = px * (160 / dpi)

Ответ 8

В большинстве случаев функции преобразования часто вызываются. Мы можем оптимизировать его, добавив memoization. Таким образом, он не вычисляет каждый раз, когда вызывается функция.

Пусть объявит HashMap, который сохранит вычисленные значения.

private static Map<Float, Float> pxCache = new HashMap<>();

Функция, которая вычисляет значения пикселей:

public static float calculateDpToPixel(float dp, Context context) {

        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        float px = dp * (metrics.densityDpi / 160f);
        return px;

    }

Функция memoization, которая возвращает значение из HashMap и сохраняет запись предыдущих значений.

Воспоминание может быть реализовано по-разному в Java. Для Java 7:

public static float convertDpToPixel(float dp, final Context context) {

        Float f = pxCache.get(dp);
        if (f == null) {
            synchronized (pxCache) {
                f = calculateDpToPixel(dp, context);
                pxCache.put(dp, f);
            }

        }

        return f;
    }

Java 8 поддерживает функцию Lambda:

public static float convertDpToPixel(float dp, final Context context) {

        pxCache.computeIfAbsent(dp, y ->calculateDpToPixel(dp,context));
}

Спасибо.

Ответ 10

Ниже были эффективны функции для всех устройств.

Это взято из https://gist.github.com/laaptu/7867851

public static float convertPixelsToDp(float px){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float dp = px / (metrics.densityDpi / 160f);
    return Math.round(dp);
}

public static float convertDpToPixel(float dp){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return Math.round(px);
}

Ответ 11

Вы можете использовать [DisplayMatrics][1] и определить плотность экрана. Что-то вроде этого:

int pixelsValue = 5; // margin in pixels
float d = context.getResources().getDisplayMetrics().density;
int margin = (int)(pixelsValue * d);

Как я помню, лучше использовать напольные покрытия для смещений и округления для ширины.

Ответ 13

//для получения в терминах Decimal/Float

public static float convertPixelsToDp(float px, Context context) {

    Resources resources = context.getResources();
    DisplayMetrics metrics = resources.getDisplayMetrics();
    float dp = px / (metrics.densityDpi / 160f);
    return Math.round(dp);
}



public static float convertDpToPixel(float dp, Context context) {
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return Math.round(px);
}


// for  getting in terms of Integer

private int convertPxToDp(int px, Context context) {
    Resources resources = context.getResources();
    return Math.round(px / (resources.getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
}


private int convertDpToPx(int dp, Context context) {
    Resources resources = context.getResources();

    return Math.round(dp * (resources.getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));

}

________________________________________________________________________________

public static float convertPixelsToDp(float px){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float dp = px / (metrics.densityDpi / 160f);
    return Math.round(dp);
}

public static float convertDpToPixel(float dp){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return Math.round(px);
}


private int convertDpToPx(int dp){
    return Math.round(dp*(getResources().getDisplayMetrics().xdpi/DisplayMetrics.DENSITY_DEFAULT));

}

private int convertPxToDp(int px){
    return Math.round(px/(Resources.getSystem().getDisplayMetrics().xdpi/DisplayMetrics.DENSITY_DEFAULT));
}

Ответ 14

Не стесняйтесь использовать этот метод, я написал:

int dpToPx(int dp)
{
    return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}

Ответ 15

Ответ, принятый выше, не совсем точно. Согласно информации, полученной при проверке исходного кода Android:

Resources.getDimension() и getDimensionPixelOffset()/getDimensionPixelSize() отличаются только тем, что первое возвращает float, а последние два возвращают одинаковое значение, округленное до int соответствующим образом. Для всех из них возвращаемое значение находится в необработанных пикселях.

Все три функции реализованы путем вызова Resources.getValue() и преобразования полученного таким образом TypedValue путем вызова TypedValue.complexToDimension(), TypedValue.complexToDimensionPixelOffset() и TypedValue.complexToDimensionPixelSize() соответственно.

Поэтому, если вы хотите получить "сырое" значение вместе с единицей, указанным в источнике XML, вызовите Resources.getValue() и используйте методы класса TypedValue.

Ответ 16

DisplayMetrics displayMetrics = contaxt.getResources()               .getDisplayMetrics();

    int densityDpi = (int) (displayMetrics.density * 160f);
    int ratio = (densityDpi / DisplayMetrics.DENSITY_DEFAULT);
    int px;
    if (ratio == 0) {
        px = dp;
    } else {
        px = Math.round(dp * ratio);

    }

Ответ 17

вариант ответа ct_robs выше, если вы используете целые числа, которые не только избегают деления на 0, но также дают полезный результат на небольших устройствах:

в целых вычислениях, включающих деление для максимальной точности, сначала умножьте сначала до деления, чтобы уменьшить эффекты усечения.

px = dp * dpi/160 dp = px * 160/dpi

5 * 120 = 600/160 = 3

вместо

5 * (120/160 = 0) = 0

если вы хотите получить округленный результат, сделайте это

px = (10 * dp * dpi/160 + 5)/10 dp = (10 * px * 160/dpi + 5)/10

10 * 5 * 120 = 6000/160 = 37 + 5 = 42/10 = 4

Ответ 18

с помощью других ответов я написал эту функцию.

public static int convertToPixels(Context context, int nDP)
{
        final float conversionScale = context.getResources().getDisplayMetrics().density; 
        return (int) ((nDP * conversionScale) + 0.5f) ;
}

Ответ 19

Вот другой способ сделать это с помощью расширений kotlin:

val Int.dpToPx: Int
    get() = Math.round(this * Resources.getSystem().displayMetrics.density)

val Int.pxToDp: Int
    get() = Math.round(this / Resources.getSystem().displayMetrics.density)

и тогда его можно использовать как угодно из любого места

12.dpToPx

244.pxToDp