Convertir píxeles a dp

827

He creado mi aplicación con la altura y el ancho dados en píxeles para un dispositivo Pantech cuya resolución es 480x800.

Necesito convertir la altura y el ancho de un dispositivo G1.
Pensé que convertirlo en dp resolvería el problema y proporcionaría la misma solución para ambos dispositivos.

¿Hay alguna manera fácil de convertir píxeles a dp?
¿Alguna sugerencia?

Indhu
fuente
1
Si está buscando hacer una conversión única (por ejemplo, para exportar sprites desde Photoshop), aquí hay un ingenioso conversor .
Paul Lammertsma

Respuestas:

1037
// 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
fuente
332
Nota: Lo anterior está convirtiendo DIP a píxeles. ¡La pregunta original preguntaba cómo convertir píxeles a Dips!
Eurig Jones
12
Aquí hay una respuesta real al OP: stackoverflow.com/questions/6656540/…
qix
119
Es curioso cómo la respuesta es más útil cuando realmente no responde la pregunta -_- ¡Pensé que quería lo que preguntaba y luego me di cuenta de que no! Muy buena respuesta. Tengo una pregunta ¿Cómo puedo obtener el último parámetro applyDimension? ¿Puedo hacer getResource().getDisplayMetrics()algo o hay algo más?
Andy
11
NOTA: operación relativamente costosa. Intente almacenar en caché los valores para un acceso más rápido
Entreco
8
Si no tiene acceso al Contextuso de objetosResources.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);
}
Muhammad Nabeel Arif
fuente
8
Podría valer la pena devolver un int Math.round (px) ya que la mayoría de los métodos esperan un valor entero
Raj Labana
3
@MuhammadBabar Esto se debe a que 160 ppp (mdpi) es la desity de línea de base a partir de la cual se calculan otras densidades. hdpi, por ejemplo, se considera que es 1,5 veces la densidad de mdpi, que en realidad es solo otra forma de decir 240 ppp. Vea la respuesta de Zsolt Safrany a continuación para todas las densidades.
Stephen
19
@TomTasche: De los documentos para Resource.getSystem()(el énfasis es mío): "Devuelve un objeto de recursos compartidos global que proporciona acceso solo a recursos del sistema (sin recursos de la aplicación) y no está configurado para la pantalla actual ( no puede usar unidades de dimensión , no cambia basado en la orientación, etc.) ".
Vicky Chijwani
2
El desarrollador tiene la opción de limitar / fijar el valor. Es mejor dar el control al desarrollador.
Muhammad Nabeel Arif
77
Yo no recomiendo DisplayMetrics.DENSITY_DEFAULTen lugar de 160f developer.android.com/reference/android/util/...
milcaepsilon
285

Preferiblemente poner en una clase 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;
}
Mike Keskinov
fuente
55
¡Esto no funciona en todos los dispositivos! El resultado de esta respuesta frente al uso de TypedValue.applyDimension no es el mismo en un OnePlus 3T (probablemente porque OnePlus tiene una escala personalizada integrada en el sistema operativo). El uso de TypedValue.applyDimension provoca un comportamiento constante en todos los dispositivos.
Ben De La Haye
197
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;

density es igual

  • .75encendido ldpi( 120ppp)
  • 1.0encendido mdpi( 160ppp; línea de base)
  • 1.5encendido hdpi( 240ppp)
  • 2.0encendido xhdpi( 320ppp)
  • 3.0encendido xxhdpi( 480ppp)
  • 4.0encendido xxxhdpi( 640ppp)

Use este convertidor en línea para jugar con los valores de dpi.

EDITAR: Parece que no hay una relación 1: 1 entre el dpicubo y density. Parece que el Nexus 5Xser xxhdpitiene un densityvalor de 2.625(en lugar de 3). Véalo usted mismo en las métricas del dispositivo .

Zsolt Safrany
fuente
3
"Parece que el Nexus 5X siendo xxhdpi tiene un valor de densidad de 2.6 (en lugar de 3)" - Técnicamente, el Nexus 5X es 420dpi y el Nexus 6 / 6P es 560dpi, ninguno aterriza directamente en uno de los cubos estándar, al igual que el Nexus 7 con tvdpi (213 ppp). Entonces, el sitio que los enumera como xxdpi y xxxhdpi es una farsa. Su gráfico ES correcto, y esos dispositivos se escalarán adecuadamente según uno de sus depósitos de ppp "especiales".
Steven Byle
108

Puedes usar esto ... sin contexto

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

Como mencionó @Stan ... el uso de este enfoque puede causar problemas si el sistema cambia la densidad. ¡Entonces sé consciente de eso!

Personalmente estoy usando Context para hacer eso. Es solo otro enfoque con el que quería compartirlo

Maher Abuthraa
fuente
11
Es posible que no quieras usar esto. Documentación para getSystem (): "Devuelve un objeto de recursos compartidos global que proporciona acceso solo a recursos del sistema (sin recursos de aplicación) y no está configurado para la pantalla actual (no puede usar unidades de dimensión, no cambia según la orientación, etc.) ".
Stan
Secundando lo que dice @Stan: esto es peligroso y no deberías usarlo, especialmente ahora cuando los factores de forma del dispositivo se están volviendo tan complejos.
Saket
93

Si puede usar las dimensiones XML, ¡es muy simple!

En su res/values/dimens.xml:

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

Luego en tu Java:

getResources().getDimensionPixelSize(R.dimen.thumbnail_height);
Alex
fuente
Dado que px a dp depende de la densidad de la pantalla, no sé cómo el OP obtuvo 120 en primer lugar, a menos que haya probado el método px a dp en todos los tamaños de pantalla diferentes.
John61590
75

De acuerdo con la Guía de desarrollo de Android:

px = dp * (dpi / 160)

Pero a menudo querrá realizar esto al revés cuando reciba un diseño que se indica en píxeles. Entonces:

dp = px / (dpi / 160)

Si está en un dispositivo de 240 ppp, esta relación es 1.5 (como se indicó anteriormente), por lo que esto significa que un icono de 60 píxeles equivale a 40 ppp en la aplicación.

Ricardo Magalhães
fuente
77
160 es constante, respuesta en la cama
usuario25
2
@ user25 Gran respuesta en realidad. ¿No has leído ningún documento en las pantallas de Android? 160 es una constante común en todo el lugar cuando se habla de densidades de pantalla de Android. Cita de documentos: "pantallas de densidad media (mdpi) (~ 160 ppp). (Esta es la densidad de referencia)". Vamos, hombre
mykolaj
70

Sin Contextmétodos estáticos elegantes:

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);
}
Adam Stelmaszczyk
fuente
24
Resources.getSystem()javadoc dice "Devuelve un objeto de recursos compartidos global que proporciona acceso solo a recursos del sistema (sin recursos de aplicación), y no está configurado para la pantalla actual (no puede usar unidades de dimensión, no cambia según la orientación, etc.)". Esto prácticamente dice que no deberías estar haciendo esto, incluso si de alguna manera funciona.
Austyn Mahoney
Acabo de leer el comentario de @ AustynMahoney y me di cuenta de que esta respuesta no es tan buena como pensaba originalmente, ¡pero SO no me deja deshacer mi voto ! Argh!
Vicky Chijwani
45

por DP to Pixel

Crea un valor en dimens.xml

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

Obtenga ese valor pixelcomo:

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

Por lo tanto, puede usar el siguiente formulador para calcular la cantidad correcta de píxeles de una dimensión especificada en 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
fuente
44
Esto convierte dp a píxeles pero llamó a su método convertToDp.
Qwertie
44
+ 0.5f se explica aquí -> developer.android.com/guide/practices/… . Se utiliza para redondear al entero más cercano.
Bae
La única respuesta correcta. puede agregar la fuente developer.android.com/guide/practices/…
user25
web.archive.org/web/20140808234241/http://developer.android.com/… para un enlace que todavía tiene el contenido en cuestión
caw
39

Para cualquiera que use Kotlin:

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

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

Uso:

64.toPx
32.toDp
Gunhan
fuente
De los documentos para Resource.getSystem (): "Devuelve un objeto de recursos compartidos global que proporciona acceso solo a recursos del sistema (sin recursos de aplicación), y no está configurado para la pantalla actual (no puede usar unidades de dimensión, no cambia en función de orientación, etc.) ".
HendraWD
@HendraWD Los documentos pueden ser confusos, las unidades de dimensión que menciona son los recursos dimens de su nivel de aplicación. displayMetrics no es un recurso de nivel de aplicación. Es un recurso del sistema y devuelve los valores correctos. Este código funciona bien en todas mis aplicaciones Prod. Nunca tuve un problema.
Gunhan
33

Hay una utilidad predeterminada en el SDK de Android: http://developer.android.com/reference/android/util/TypedValue.html

float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
Kvant
fuente
Deberías estar usando este. Como beneficio adicional también hará SP.
Mark Renouf
2
resultPixdebe ser de tipo int. int resultPix = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
vovahost
27

usando kotlin-extension lo hace mejor

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

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

ACTUALIZAR:

Debido a que displayMetricses parte de los recursos globales compartidos , podemos usarResources.getSystem()

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

fun Int.toDp(): Int = (this / Resources.getSystem().displayMetrics.density).toInt()
Beigirad
fuente
44
¿Por qué lo agregarías como una extensión de Int? La responsabilidad no tiene que hacer nada con el tipo Int.
htafoya
19

Esto debería darle la conversión dp a píxeles:

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

Esto debería darle los píxeles de conversión a dp:

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

Kotlin

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);
}
Khemraj
fuente
12

Probablemente la mejor manera si tiene la dimensión dentro de los valores / dimen es obtener la dimensión directamente del método getDimension (), le devolverá la dimensión ya convertida en valor de píxel.

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

Solo para explicar mejor esto,

getDimension(int resourceId) 

devolverá la dimensión ya convertida a píxel COMO UN FLOTADOR.

getDimensionPixelSize(int resourceId)

devolverá lo mismo pero truncado a int, así que COMO UN INTEGER.

Ver referencia de Android

Lorenzo Barbagli
fuente
9
Para convertir dp a píxel.
public static int dp2px(Resources resource, int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,   dp,resource.getDisplayMetrics());
}
Para convertir píxeles a dp.
  public static float px2dp(Resources resource, float px)  {
    return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}

donde recurso es context.getResources ().

Príncipe Gupta
fuente
8
La respuesta es incorrecta, porque no estás convirtiendo píxeles a dp, ¡estás convirtiendo píxeles a píxeles!
Yaroslav
El px4dp es incorrecto: devolverá el mismo valor en píxeles.
Natario
8

Me gusta esto:

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

depende del contexto, valor de retorno de flotación, método estático

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

Trinea
fuente
8

Enfoque más elegante usando la función de extensión de 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()

Uso:

println("16 dp in pixel: ${16.dpToPx}")
println("16 px in dp: ${16.pxToDp}")
Saeed Masoumi
fuente
Me encanta el uso de la extensión aquí. Leí las funciones como "convertir a function name", que me doy cuenta de que está al revés en este caso. Para aclarar la intención de cada función, los nombres de las funciones podrían actualizarse para leer dpToPx y pxToDp, respectivamente.
Maxwell
De los documentos para Resource.getSystem (): "Devuelve un objeto de recursos compartidos global que proporciona acceso solo a recursos del sistema (sin recursos de aplicación), y no está configurado para la pantalla actual (no puede usar unidades de dimensión, no cambia en función de orientación, etc.) ".
HendraWD
7
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);
Sibin
fuente
2
¿No es esto lo que está cubierto en muchas de las otras respuestas a esta pregunta?
TZHX
7

En caso de que desarrolle una aplicación crítica de rendimiento, considere la siguiente clase optimizada:

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;
    }
}
Pavel
fuente
Tiene sentido solo si realiza conversiones con mucha frecuencia. En mi caso lo hago.
Pavel
¿Qué es 160f? ¿Por qué lo usas, por qué es 160?
dephinera
160 => 160 ppp y esto es para convertir medidas debido a la fórmula
xAqweRx
6

para convertir píxeles a dp use TypedValue .

Como se menciona en la documentación: Contenedor para un valor de datos con tipo dinámico.

y use el método applyDimension :

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

que convierte un valor de datos complejos desempaquetado que contiene una dimensión a su valor final de coma flotante como el siguiente:

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

Espero que ayude .


fuente
6

Así es como funciona para mí:

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

Puedes hacer lo mismo para el ancho.

Temi Mide Adey
fuente
4

Debe usar dp tal como lo haría con los píxeles. Eso es todo lo que son; Mostrar píxeles independientes. Use los mismos números que usaría en una pantalla de densidad media, y el tamaño será mágicamente correcto en una pantalla de alta densidad.

Sin embargo, parece que lo que necesita es la opción fill_parent en su diseño de diseño. Use fill_parent cuando desee que su vista o control se expanda a todo el tamaño restante en el contenedor principal.

Michael Lowman
fuente
en realidad mi problema es mi solicitud se codifica para la pantalla de alta densidad y ahora tiene que ser convertido a la pantalla de baja densidad ..
Indhu
modifique sus píxeles para una pantalla de densidad media (puede configurar una pantalla de densidad media en el emulador) y reemplace el píxel con dp. Sin embargo, se pueden hacer aplicaciones más flexibles usando fill_parent y diseños múltiples.
Michael Lowman
Finalmente, no tuve más opción que cambiar todos los px a dp manualmente .. :(
Indhu
1
Al menos la próxima vez usará dp primero y no tendrá que cambiar nada :) Aunque debería ser posible usar diseños que no requieran un posicionamiento absoluto para la mayoría de las cosas.
Michael Lowman
Como era mi primera aplicación ... cometí este error ... nunca lo volveré a hacer ... :)
Indhu
4

PXy DPson diferentes pero similares.

DPes la resolución cuando solo se factoriza el tamaño físico de la pantalla. Cuando lo use DP, escalará su diseño a otras pantallas de tamaño similar con diferentespixel densidades.

Ocasionalmente pixels, sin embargo, realmente desea , y cuando trata con dimensiones en código, siempre está tratando con real pixels, a menos que las convierta.

Entonces, en un dispositivo Android, hdpipantalla de tamaño normal , 800x480 is 533x320en DP(creo). Para convertir DPen pixels /1.5, para volver a convertir *1.5. Esto es solo para el tamaño de una pantalla y dpicambiaría según el diseño. Sin pixelsembargo, nuestros artistas me dan y me convierto DPcon la 1.5ecuación anterior .

HaMMeReD
fuente
3

Si desea valores enteros , use Math.round () redondeará el flotante al entero más cercano.

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

La mejor respuesta proviene del propio marco de Android: solo use esta igualdad ...

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

(convierte dp a px)

JarsOfJam-Scheduler
fuente
2

Esto funciona para mí (C #):

int pixels = (int)((dp) * Resources.System.DisplayMetrics.Density + 0.5f);
Michael Zhang
fuente
No es una respuesta a esta pregunta, pero para C # funciona. Gracias
Yekmer Simsek
2

Kotlin

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