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

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

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

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

36 ответов

// Converts 14 dip into its equivalent px
float dip = 14f;
Resources r = getResources();
float px = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP,
    dip,
    r.getDisplayMetrics()
);
/**
 * 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){
    Resources resources = context.getResources();
    DisplayMetrics metrics = resources.getDisplayMetrics();
    float px = dp * ((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
    return px;
}

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

Предпочтительно помещать в класс 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;
}
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). Убедитесь сами в метриках устройства.

Вы можете использовать это.. без контекста

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, использование этого подхода может вызвать проблемы, если система изменит плотность. Так что знайте об этом!

Лично я использую контекст, чтобы сделать это.

Если вы можете использовать измерения 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);

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

px = dp * (dpi / 160)

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

dp = px / (dpi / 160)

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

Без 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);
}

Использование 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()

ЗаDP to Pixel

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

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

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

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

Для тех, кто использует 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

Поэтому вы можете использовать следующий составитель для вычисления правильного количества пикселей по измерению, указанному в 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);
}

В Android SDK есть утилита по умолчанию: http://developer.android.com/reference/android/util/TypedValue.html

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

Котлин

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

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

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

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

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

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

getDimension(int resourceId) 

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

getDimensionPixelSize(int resourceId)

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

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

Чтобы преобразовать дп в пиксель.
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().

Котлин

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

Как это:

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

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

Чтобы конвертировать пиксели в 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());

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

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

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

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

Много отличных решений выше. Однако лучшее решение, которое я нашел, это дизайн Google:

https://design.google.com/devices/

плотность

Вот как это работает для меня:

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

Вы можете сделать то же самое для ширины.

Вы должны использовать dp так же, как и пиксели. Это все, что они есть; отображать независимые пиксели. Используйте те же числа, что и на экране средней плотности, и размер будет магически правильным на экране высокой плотности.

Однако, похоже, вам нужна опция fill_parent в вашем макете. Используйте fill_parent, когда вы хотите, чтобы ваше представление или элемент управления расширились до всех оставшихся размеров в родительском контейнере.

private fun toDP(context: Context,value: Int): Int {
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
        value.toFloat(),context.resources.displayMetrics).toInt()
}

PX а также DP разные, но похожие.

DP разрешение, когда вы учитываете только физический размер экрана. Когда вы используете DP он будет масштабировать ваш макет на другие похожие по размеру экраны с pixel плотности.

Иногда вы действительно хотите pixels хотя, и когда вы имеете дело с измерениями в коде, вы всегда имеете дело с реальным pixels, если вы не конвертируете их.

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

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

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

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

Другие вопросы по тегам