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?


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

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

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

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 .


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


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

É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.



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

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

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

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

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


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

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

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

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


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 ().


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


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

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

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

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 .


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.



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.


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 .


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

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)


2

Cela fonctionne pour moi (C #):

int pixels = (int)((dp) * Resources.System.DisplayMetrics.Density + 0.5f);

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;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.