Conversion de pixels en dp

827

J'ai créé mon application avec la hauteur et la largeur données en pixels pour un appareil Pantech dont la résolution est 480x800.

Je dois convertir la hauteur et la largeur d'un appareil G1.
Je pensais que le convertir en dp résoudrait le problème et fournirait la même solution pour les deux appareils.

Existe-t-il un moyen simple de convertir des pixels en dp?
Aucune suggestion?

Indhu
la source
1
Si vous cherchez à faire une conversion unique (par exemple pour exporter des sprites depuis Photoshop), voici un convertisseur astucieux .
Paul Lammertsma

Réponses:

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
la source
332
Remarque: ce qui précède convertit les DIP en pixels. La question d'origine demandait comment convertir les pixels en Dips!
Eurig Jones
12
Voici une vraie réponse à l'OP: stackoverflow.com/questions/6656540/…
qix
119
C'est drôle à quel point la réponse est plus utile quand elle ne répond pas vraiment à la question -_- J'ai pensé que je voulais ce que la question demandait, puis j'ai réalisé que je ne l'avais pas! Tellement bonne réponse. J'ai une question. Comment puis-je obtenir le dernier paramètre pour applyDimension? Puis-je simplement faire getResource().getDisplayMetrics(), ou y a-t-il autre chose?
Andy
11
REMARQUE: opération relativement coûteuse. Essayez de mettre en cache les valeurs pour un accès plus rapide
Entreco
8
Si vous n'avez pas accès à l' Contextutilisation d'objetsResources.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
la source
8
Cela pourrait valoir la peine de renvoyer un entier Math.round (px) car la plupart des méthodes s'attendent à une valeur entière
Raj Labana
3
@MuhammadBabar En effet, 160 dpi (mdpi) est la divinité de base à partir de laquelle les autres densités sont calculées. hdpi par exemple est considéré comme 1,5 fois la densité de mdpi, ce qui n'est vraiment qu'une autre façon de dire 240 dpi. Voir la réponse de Zsolt Safrany ci-dessous pour toutes les densités.
Stephen
19
@TomTasche: À partir de la documentation de Resource.getSystem()(accent sur le mien): "Retourne un objet global shared Resources qui donne accès aux seules ressources système (pas de ressources d'application), et n'est pas configuré pour l'écran actuel ( ne peut pas utiliser les unités de dimension , ne change pas basé sur l'orientation, etc.). "
Vicky Chijwani
2
Le développeur a le choix de plafonner / plancher la valeur. Il vaut mieux donner le contrôle au développeur.
Muhammad Nabeel Arif
7
Je recommanderais à la DisplayMetrics.DENSITY_DEFAULTplace de 160f developer.android.com/reference/android/util/…
milcaepsilon
285

Mettez de préférence dans une classe 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
la source
5
Cela ne fonctionne pas sur tous les appareils! Le résultat de cette réponse par rapport à celui de l'utilisation de TypedValue.applyDimension n'est pas le même sur un OnePlus 3T (probablement parce que OnePlus a une mise à l'échelle personnalisée intégrée dans le système d'exploitation). L'utilisation de TypedValue.applyDimension provoque un comportement cohérent sur tous les appareils.
Ben De La Haye
197
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;

density équivaut à

  • .75le ldpi( 120dpi)
  • 1.0sur mdpi( 160dpi; base)
  • 1.5le hdpi( 240dpi)
  • 2.0le xhdpi( 320dpi)
  • 3.0le xxhdpi( 480dpi)
  • 4.0le xxxhdpi( 640dpi)

Utilisez ce convertisseur en ligne pour jouer avec les valeurs dpi.

EDIT: Il semble qu'il n'y ait pas de relation 1: 1 entre le dpiseau et density. Il semble que l' Nexus 5Xêtre xxhdpiait une densityvaleur de 2.625(au lieu de 3). Voyez par vous-même dans les métriques de l' appareil .

Zsolt Safrany
la source
3
"Il semble que le Nexus 5X soit xxhdpi a une valeur de densité de 2,6 (au lieu de 3)" - Techniquement, le Nexus 5X est de 420 dpi et le Nexus 6 / 6P est de 560 dpi, ni atterrir directement dans l'un des godets standard, tout comme le Nexus 7 avec tvdpi (213dpi). Ainsi, le site répertoriant ceux-ci en tant que xxdpi et xxxhdpi est une farce. Votre graphique EST correct, et ces appareils seront correctement mis à l'échelle en fonction de leurs compartiments dpi "spéciaux".
Steven Byle
108

Vous pouvez l'utiliser .. sans contexte

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

Comme @Stan l'a mentionné .. l'utilisation de cette approche peut entraîner des problèmes si le système change de densité. Alors soyez conscient de ça!

Personnellement, j'utilise Context pour cela. C'est juste une autre approche avec laquelle je voulais vous partager

Maher Abuthraa
la source
11
Vous ne voudrez peut-être pas l'utiliser. Documentation pour getSystem () - "Renvoyer un objet global shared Resources qui donne accès uniquement aux ressources système (pas de ressources d'application) et qui n'est pas configuré pour l'écran actuel (ne peut pas utiliser les unités de dimension, ne change pas en fonction de l'orientation, etc.) . "
Stan
Appuyant sur ce que dit @Stan: c'est dangereux et vous ne devriez pas l'utiliser, surtout maintenant lorsque les facteurs de forme des appareils deviennent si complexes.
Saket
93

Si vous pouvez utiliser les dimensions XML, c'est très simple!

Dans votre res/values/dimens.xml:

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

Puis dans votre Java:

getResources().getDimensionPixelSize(R.dimen.thumbnail_height);
Alex
la source
Étant donné que px en dp dépend de la densité de l'écran, je ne sais pas comment l'OP a obtenu 120 en premier lieu, à moins qu'il ou elle n'ait testé la méthode px to dp sur toutes les différentes tailles d'écran.
John61590
75

Selon le Guide de développement Android:

px = dp * (dpi / 160)

Mais souvent, vous voudrez effectuer cette opération dans l'autre sens lorsque vous recevrez un design exprimé en pixels. Donc:

dp = px / (dpi / 160)

Si vous utilisez un appareil à 240 dpi, ce rapport est de 1,5 (comme indiqué précédemment), cela signifie donc qu'une icône de 60 pixels équivaut à 40 dpi dans l'application.

Ricardo Magalhães
la source
2
Indhu, vous pouvez vous référer ici developer.android.com/guide/practices/… et developer.android.com/reference/android/util/…
Sachchidanand
7
160 est constant, réponse au lit
user25
2
@ user25 Excellente réponse en fait. N'avez-vous pas lu de documents sur les écrans Android? 160 est une constante commune partout quand on parle de densité d'écran Android. Citation de documents: "Écrans de densité moyenne (mdpi) (~ 160dpi). (Il s'agit de la densité de base)". Allez, mec
mykolaj
70

Sans Contextméthodes statiques élégantes:

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
la source
24
Resources.getSystem()javadoc dit "Renvoyer un objet global de ressources partagées qui donne accès uniquement aux ressources système (pas de ressources d'application) et n'est pas configuré pour l'écran actuel (ne peut pas utiliser les unités de dimension, ne change pas en fonction de l'orientation, etc.)." Cela indique à peu près que vous ne devriez pas faire cela même si cela fonctionne d'une manière ou d'une autre.
Austyn Mahoney
Je viens de lire le commentaire de @ AustynMahoney et j'ai réalisé que cette réponse n'était pas aussi bonne que je le pensais à l'origine, mais SO ne me laissera pas annuler mon vote positif ! Argh!
Vicky Chijwani du
45

Pour DP to Pixel

Créer une valeur dans dimens.xml

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

Obtenez cette valeur en pixeltant que:

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

Vous pouvez donc utiliser le formulateur suivant pour calculer la bonne quantité de pixels à partir d'une dimension spécifiée 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
la source
4
Cela convertit dp en pixels mais vous avez appelé votre méthode convertToDp.
Qwertie
4
+ 0.5f est expliqué ici -> developer.android.com/guide/practices/… . Il est utilisé pour arrondir à l'entier le plus proche.
Bae
la seule bonne réponse. vous pouvez ajouter la source developer.android.com/guide/practices/…
user25
web.archive.org/web/20140808234241/http://developer.android.com/… pour un lien qui a toujours le contenu en question
caw
39

Pour toute personne utilisant Kotlin:

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

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

Usage:

64.toPx
32.toDp
Gunhan
la source
A partir des documents pour Resource.getSystem (): "Renvoyer un objet global shared Resources qui donne accès uniquement aux ressources système (pas de ressources d'application) et qui n'est pas configuré pour l'écran actuel (ne peut pas utiliser les unités de dimension, ne change pas en fonction de orientation, etc.). "
HendraWD
@HendraWD Les documents peuvent prêter à confusion, les unités de dimension qu'il mentionne sont vos ressources dimens de niveau d'application. displayMetrics n'est pas une ressource de niveau application. Il s'agit d'une ressource système et elle renvoie les valeurs correctes. Ce code fonctionne correctement sur toutes mes applications Prod. Jamais eu de problème.
Gunhan
33

Il existe un utilitaire par défaut dans le SDK Android: http://developer.android.com/reference/android/util/TypedValue.html

float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
Kvant
la source
Vous devriez utiliser celui-ci. En bonus, il fera également SP.
Mark Renouf
2
resultPixdoit être de type int. int resultPix = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
vovahost
27

utiliser kotlin-extension le rend meilleur

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

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

MISE À JOUR:

En raison de displayMetricsfait partie des ressources partagées mondiales , nous pouvons utiliserResources.getSystem()

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

fun Int.toDp(): Int = (this / Resources.getSystem().displayMetrics.density).toInt()
beigirad
la source
4
Pourquoi voudriez-vous l'ajouter en tant qu'extension d'Int, la responsabilité n'a rien à faire avec le type Int.
htafoya
19

Cela devrait vous donner la conversion dp en pixels:

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

Cela devrait vous donner les pixels de conversion en dp:

public static int pxToDp(int px)
{
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
Venki WAR
la source
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
la source
12

Probablement la meilleure façon si vous avez la dimension à l'intérieur des valeurs / dimen est d'obtenir la dimension directement à partir de la méthode getDimension (), elle vous renverra la dimension déjà convertie en valeur de pixel.

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

Juste pour mieux expliquer cela,

getDimension(int resourceId) 

renverra la dimension déjà convertie en pixel COMME UN FLOTTEUR.

getDimensionPixelSize(int resourceId)

retournera le même mais tronqué à int, donc COMME UN ENTIER.

Voir la référence Android

Lorenzo Barbagli
la source
9
Pour convertir dp en pixel.
public static int dp2px(Resources resource, int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,   dp,resource.getDisplayMetrics());
}
Pour convertir le pixel en dp.
  public static float px2dp(Resources resource, float px)  {
    return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}

où ressource est context.getResources ().

Prince Gupta
la source
8
La réponse est fausse, car vous ne convertissez pas les pixels en dp - vous convertissez les pixels en pixels!
Yaroslav
Le px2dp est incorrect - renverra la même valeur en pixels.
natario
8

comme ça:

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

dépend du contexte, retourne la valeur flottante, méthode statique

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

Trinea
la source
8

Approche plus élégante utilisant la fonction d'extension 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()

Usage:

println("16 dp in pixel: ${16.dpToPx}")
println("16 px in dp: ${16.pxToDp}")
Saeed Masoumi
la source
J'adore l'utilisation de l'extension ici. J'ai lu les fonctions comme "convertir en function name" qui je me rends compte à l'envers dans ce cas. Pour clarifier l'intention de chaque fonction, les noms des fonctions pourraient être mis à jour pour lire respectivement dpToPx et pxToDp.
Maxwell
A partir des documents pour Resource.getSystem (): "Renvoyer un objet global shared Resources qui donne accès uniquement aux ressources système (pas de ressources d'application) et qui n'est pas configuré pour l'écran actuel (ne peut pas utiliser les unités de dimension, ne change pas en fonction de orientation, etc.). "
HendraWD
7
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);
Sibin
la source
2
N'est-ce pas simplement la même chose que ce qui est couvert dans de nombreuses autres réponses à cette question?
TZHX
7

Si vous développez une application critique pour les performances, veuillez considérer la classe optimisée suivante:

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
la source
Cela n'a de sens que si vous effectuez des conversions très fréquemment. Dans mon cas, je le fais.
Pavel
Qu'est-ce que 160f? Pourquoi l'utilisez-vous, pourquoi est-il 160?
dephinera
160 => 160 dpi et ceci pour convertir des mesures en raison de la formule
xAqweRx
6

pour convertir des pixels en dp, utilisez TypedValue .

Comme mentionné dans la documentation: Conteneur pour une valeur de données typée dynamiquement.

et utilisez la méthode applyDimension :

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

qui convertit une valeur de données complexes non compressée contenant une dimension en sa valeur finale en virgule flottante comme suit:

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

J'espère que cela pourra aider .


la source
6

Voici comment cela fonctionne pour moi:

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

Vous pouvez faire de même pour la largeur.

Temi Mide Adey
la source
4

Vous devez utiliser dp comme vous le feriez avec des pixels. C'est tout ce qu'ils sont; afficher des pixels indépendants. Utilisez les mêmes nombres que vous le feriez sur un écran de densité moyenne, et la taille sera magiquement correcte sur un écran de haute densité.

Cependant, il semble que vous ayez besoin de l'option fill_parent dans votre conception de mise en page. Utilisez fill_parent lorsque vous souhaitez que votre vue ou contrôle s'étende à toute la taille restante dans le conteneur parent.

Michael Lowman
la source
en fait mon problème est que mon application est codée pour un écran haute densité et maintenant elle doit être convertie en écran basse densité ..
Indhu
modifiez vos pixels pour un écran de densité moyenne (vous pouvez configurer un écran de densité moyenne dans l'émulateur) et remplacez le pixel par dp. Cependant, des applications plus flexibles peuvent être faites en utilisant fill_parent et plusieurs dispositions.
Michael Lowman
Enfin, je n'avais pas d'autre choix que de changer tous les px en dp manuellement .. :(
Indhu
1
Au moins la prochaine fois, vous utiliserez dp en premier et vous n'aurez rien à changer :) Bien qu'il devrait être possible d'utiliser des mises en page qui ne nécessitent pas de positionnement absolu pour la plupart des choses.
Michael Lowman,
Puisque c'était ma première application .. j'ai fait cette erreur ... je ne le referai plus jamais ... :)
Indhu
4

PXet DPsont différents mais similaires.

DPest la résolution lorsque vous ne tenez compte que de la taille physique de l'écran. Lorsque vous l'utilisez DP, votre disposition sera mise à l'échelle sur d'autres écrans de taille similaire avec des pixeldensités différentes .

Parfois, vous le souhaitez pixels, et lorsque vous traitez avec des dimensions dans du code, vous traitez toujours avec de la réalité pixels, sauf si vous les convertissez.

Donc, sur un appareil Android, un hdpiécran de taille normale , 800x480 is 533x320en DP(je crois). Pour convertir DPen pixels /1.5, pour reconvertir *1.5. Ce n'est que pour la taille d'écran unique dpi, et cela changerait selon la conception. Nos artistes me donnent pixelscependant et je me convertis à DPl' 1.5équation ci-dessus .

HaMMeReD
la source
3

Si vous voulez des valeurs entières , l'utilisation de Math.round () arrondira le flottant à l'entier le plus proche.

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

La meilleure réponse vient du framework Android lui-même: utilisez simplement cette égalité ...

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

(convertit dp en px)

JarsOfJam-Scheduler
la source
2

Cela fonctionne pour moi (C #):

int pixels = (int)((dp) * Resources.System.DisplayMetrics.Density + 0.5f);
Michael Zhang
la source
Pas une réponse à cette question mais pour C # ça marche. Merci
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
la source