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

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

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

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

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

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

21 ответ

Решение

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

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

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

Преобразовать дп в пиксель:

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

Преобразовать пиксель в дп:

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

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

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

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

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

DP to Pixel:

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

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

px до dp:

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

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

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

private int dp2px(int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
px = dp * (dpi / 160)

dp = px * (160 / dpi)

Используйте эти расширения Kotlin:

/**
 * Converts Pixel to DP.
 */
val Int.pxToDp: Int
    get() = (this / Resources.getSystem().displayMetrics.density).toInt()

/**
 * Converts DP to Pixel.
 */
val Int.dpToPx: Int
    get() = (this * Resources.getSystem().displayMetrics.density).toInt()

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

Давайте объявим 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;

    }

Функция запоминания, которая возвращает значение из 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));
}

Благодарю.

Элегантное котлин-решение :)

      val Int.dp get() = this / (Resources.getSystem().displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
val Float.dp get() = this / (Resources.getSystem().displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)

val Int.px get() = this * Resources.getSystem().displayMetrics.density
val Float.px get() = this * Resources.getSystem().displayMetrics.density

Применение:

      val dpValue = 2.dp
val pxFromDpValue = 2.px

Важно:

я не уверен, если Resources.getSystem()будет корректно работать с изменением ориентации.

Если вы хотите работать, например, с фрагментом или действием, просто добавьте его в базовый фрагмент или базовое действие и используйте его следующим образом:

      abstract class BaseFragment : Fragment() {

    val Int.dp get() = this / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
    val Float.dp get() = this / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)

    val Int.px get() = this * resources.displayMetrics.density
    val Float.px get() = this * resources.displayMetrics.density

    .......
}

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

Это взято от 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);
}

// для получения в виде десятичной дроби

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

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

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

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

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

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

    }

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

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

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

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

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

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

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

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

Вариант 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

Вот другой способ сделать это с помощью расширений 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
Другие вопросы по тегам