Question

Je suis en train de calculer une quantité variable de pixels à la densité des pixels indépendants et vice-versa.

Cette formule (px to dp): dp = (int)(px / (displayMetrics.densityDpi / 160)); ne fonctionne pas sur les petits appareils, car il est divisé par zéro.

Ceci est mon dp à la formule px:

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

Quelqu'un pourrait-il me donner quelques conseils?

Était-ce utile?

La solution

Note: La solution largement utilisée ci-dessus est basée sur displayMetrics.density. Cependant, les documents expliquent que cette valeur est une valeur arrondie, utilisée avec l'écran « seaux ». Par exemple. sur mon Nexus 10, il retourne 2, où la valeur réelle serait 298dpi (réel) / 160dpi (par défaut) = 1,8625.

En fonction de vos besoins, vous pourriez avoir besoin de la transformation exacte, ce qui peut être atteint comme ceci:

[Modifier] Ce n'est pas destiné à être mélangé à l'unité interne dp Android, comme cela est bien sûr toujours sur la base des seaux d'écran. Utilisez ce où vous voulez une unité qui devrait rendre la même taille réelle sur différents appareils.

Convertir dp à pixel:

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

pixel Convertir dp:

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

Notez qu'il existe xdpi et propriétés ydpi, vous pourriez vouloir distinguer, mais je ne peux pas imaginer un affichage sain d'esprit où ces valeurs sont très différentes.

Autres conseils

Je résolu mon problème en utilisant les formules suivantes. Que d'autres personnes en bénéficier.

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

px à dp:

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

Il suffit d'appeler getResources().getDimensionPixelSize(R.dimen.your_dimension) convertir les unités de dp aux pixels

Manière efficace jamais

DP de pixels:

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

Pixel pour DP

private int pxToDp(int px)
{
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}

Espérons que cela vous aidera.

Cette fonction

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

dp = px * (160 / dpi)

Dans la plupart des cas, les fonctions de conversion sont appelés fréquemment. Nous pouvons l'optimiser en ajoutant memoization. Ainsi, il ne calcule pas tous les temps la fonction est appelée.

Soit de la Déclarez une HashMap qui permet de stocker les valeurs calculées.

private static Map<Float, Float> pxCache = new HashMap<>();

Une fonction qui calcule des valeurs de pixel:

public static float calculateDpToPixel(float dp, Context context) {

        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        float px = dp * (metrics.densityDpi / 160f);
        return px;

    }

Une fonction de memoization qui renvoie la valeur de HashMap et maintient l'enregistrement de valeurs précédentes.

Memoization peut être mis en œuvre de différentes manières en Java. Pour 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 prend en charge la fonction Lambda :

public static float convertDpToPixel(float dp, final Context context) {

        pxCache.computeIfAbsent(dp, y ->calculateDpToPixel(dp,context));
}

Merci.

Ci-dessous funtions a bien fonctionné pour moi sur tous les appareils.

Il est tiré de 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);
}

Vous pouvez utiliser [DisplayMatrics][1] et déterminer la densité de l'écran. Quelque chose comme ceci:

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

Je me souviens qu'il est préférable d'utiliser des planchers pour des décalages et arrondis pour les largeurs.

Si vous êtes à la recherche d'une calculatrice en ligne pour convertir DP, SP, pouces, millimètres, points ou pixels et d'une autre à différentes densités d'écran, Ceci est l'outil le plus complet que je connaisse .

// pour obtenir en termes de décimal / Float

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

Ne hésitez pas à utiliser cette méthode que j'ai écrit:

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

La réponse acceptée ci-dessus ne sont pas tout à fait exact. Selon les informations obtenues en examinant le code source Android:

Resources.getDimension() et getDimensionPixelOffset() / getDimensionPixelSize() diffèrent seulement en ce que les anciens rendements float tandis que les deux derniers retour la même valeur arrondie à int appropriatelly. Pour chacun d'eux, la valeur de retour est en pixels premières.

Toutes les trois fonctions sont implementedy en appelant Resources.getValue() et convertir TypedValue ainsi obtenu en appelant TypedValue.complexToDimension(), TypedValue.complexToDimensionPixelOffset() et TypedValue.complexToDimensionPixelSize(), respectivement.

Par conséquent, si vous voulez obtenir une valeur « brute » en même temps que l'unité spécifiée dans la source XML, appel Resources.getValue() et méthodes d'utilisation de la classe TypedValue.

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

    }

variation sur ct_robs réponse ci-dessus, si vous utilisez des entiers, non seulement évite de diviser par 0, il produit également un résultat utilisable sur les petits appareils:

dans les calculs entiers impliquant la division se multiplient d'abord pour une plus grande précision avant de se diviser pour réduire les effets de troncature.

px = dp * dpi / 160 dp = px * 160 / dpi

5 * 120 = 600/160 = 3

au lieu de

5 * (120/160 = 0) = 0

si vous voulez résultat arrondi le faire

px = (10 * * dp dpi / 160 + 5) / 10 dp = (10 * px * 160 / dpi + 5) / 10

5 * 10 * 120 = 6000/160 = 37 + 5 = 42/10 = 4

avec l'aide d'autres réponses que j'ai écrit cette fonction.

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

Voici une autre façon de le faire en utilisant les extensions de 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)

et alors il peut être utilisé comme ceci où que vous soyez

12.dpToPx

244.pxToDp
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top