Convertendo pixels em dp

827

Eu criei meu aplicativo com a altura e largura fornecidas em pixels para um dispositivo Pantech cuja resolução é 480x800.

Preciso converter altura e largura para um dispositivo G1.
Eu pensei que convertê-lo em dp resolverá o problema e fornecerá a mesma solução para os dois dispositivos.

Existe alguma maneira fácil de converter pixels em dp?
Alguma sugestão?

Indhu
fonte
1
Se você deseja fazer uma conversão única (por exemplo, para exportar sprites do Photoshop), aqui está um conversor bacana .
Paul Lammertsma

Respostas:

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
fonte
332
Nota: O acima está convertendo DIPs em pixels. A pergunta original perguntou como converter pixels em Dips!
Eurig Jones 13/03/12
12
Aqui está uma resposta real para o OP: stackoverflow.com/questions/6656540/...
qix
119
É engraçado como a resposta é mais útil quando realmente não responde à pergunta -_- Eu pensei que queria o que a pergunta fazia, então percebi que não! Ótima resposta. Eu tenho uma pergunta. Como posso obter o último parâmetro para applyDimension? Posso fazer getResource().getDisplayMetrics()ou há algo mais?
Andy
11
NOTA: operação relativamente cara. Tente armazenar em cache os valores para um acesso mais rápido
Entreco
8
Se não têm acesso ao Contextuso de objetoResources.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
fonte
8
Pode valer a pena retornar um int Math.round (px) como a maioria dos métodos de esperar um valor inteiro
Raj Labana
3
@MuhammadBabar Isso ocorre porque 160 dpi (mdpi) é a unidade base da qual outras densidades são calculadas. O hdpi, por exemplo, é considerado 1,5x a densidade do mdpi, que é realmente apenas outra maneira de dizer 240 dpi. Veja a resposta da Zsolt Safrany abaixo para todas as densidades.
Stephen
19
@TomTasche: Dos documentos para Resource.getSystem()(ênfase minha): "Retorne um objeto Global compartilhado de Recursos que fornece acesso apenas aos recursos do sistema (sem recursos de aplicativos) e não está configurado para a tela atual ( não pode usar unidades de dimensão , não muda com base na orientação, etc) ".
Vicky Chijwani
2
O desenvolvedor tem a opção de limitar / limitar o valor. É melhor dar controle ao desenvolvedor.
Muhammad Nabeel Arif
7
Eu recomendo DisplayMetrics.DENSITY_DEFAULTem vez de 160f developer.android.com/reference/android/util/...
milcaepsilon
285

Coloque preferencialmente em uma 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
fonte
5
Isso não funciona em todos os dispositivos! O resultado desta resposta em relação ao uso de TypedValue.applyDimension não é o mesmo no OnePlus 3T (provavelmente porque o OnePlus possui dimensionamento personalizado incorporado ao sistema operacional). O uso de TypedValue.applyDimension causa um comportamento consistente entre os dispositivos.
Ben De La Haye
197
float density = context.getResources().getDisplayMetrics().density;
float px = someDpValue * density;
float dp = somePxValue / density;

density é igual a

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

Use este conversor online para brincar com os valores de dpi.

EDIT: Parece que não há relação 1: 1 entre dpibucket e density. Parece que o Nexus 5Xser xxhdpitem um densityvalor de 2.625(em vez de 3). Veja você mesmo nas Métricas do dispositivo .

Zsolt Safrany
fonte
3
"Parece que o Nexus 5X sendo xxhdpi tem um valor de densidade de 2,6 (em vez de 3)" - Tecnicamente, o Nexus 5X tem 420dpi e o Nexus 6 / 6P é 560dpi, nem pousa diretamente em um dos baldes padrão, assim como o Nexus 7 com tvdpi (213 dpi). Portanto, o site que lista aqueles como xxdpi e xxxhdpi é uma farsa. Seu gráfico está correto e esses dispositivos serão dimensionados adequadamente com base em seus baldes de dpi "especiais".
Steven Byle
108

Você pode usar isso .. sem 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 o @Stan mencionou .. usar essa abordagem pode causar problemas se o sistema alterar a densidade. Então, fique ciente disso!

Pessoalmente, estou usando o Contexto para fazer isso. É apenas outra abordagem com a qual eu queria compartilhar você

Maher Abuthraa
fonte
11
Você pode não querer usar isso. Documentação para getSystem () - "Retorna um objeto Global compartilhado de Recursos que fornece acesso apenas aos recursos do sistema (sem recursos do aplicativo) e não está configurado para a tela atual (não pode usar unidades de dimensão, não muda com base na orientação, etc.) . "
Stan
Afastando o que @Stan está dizendo: isso é perigoso e você não deve usá-lo, especialmente agora quando os fatores de forma do dispositivo estão se tornando tão complexos.
Saket
93

Se você pode usar o XML das dimensões, é muito simples!

No seu res/values/dimens.xml:

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

Então no seu Java:

getResources().getDimensionPixelSize(R.dimen.thumbnail_height);
Alex
fonte
Como px para dp depende da densidade da tela, não sei como o OP obteve 120 em primeiro lugar, a menos que ele tenha testado o método px para dp em todos os tamanhos de tela diferentes.
precisa saber é o seguinte
75

De acordo com o Guia de desenvolvimento do Android:

px = dp * (dpi / 160)

Mas, muitas vezes, você deseja fazer isso de maneira inversa ao receber um design declarado em pixels. Assim:

dp = px / (dpi / 160)

Se você estiver em um dispositivo de 240 dpi, essa proporção é de 1,5 (como mencionado anteriormente), então isso significa que um ícone de 60px é igual a 40dp no aplicativo.

Ricardo Magalhães
fonte
7
160 é constante, a resposta cama
USER25
2
@ user25 Ótima resposta, na verdade. Você não leu nenhum documento nas telas do Android? 160 é uma constante comum em todo o lugar quando se fala em densidades de tela do Android. Citação de documentos: "telas de densidade média (mdpi) (~ 160dpi). (Essa é a densidade da linha de base)". Vamos lá, cara
mykolaj
70

Sem 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
fonte
24
Resources.getSystem()javadoc diz "Retorne um objeto Global compartilhado de Recursos que fornece acesso apenas aos recursos do sistema (sem recursos do aplicativo) e não está configurado para a tela atual (não pode usar unidades de dimensão, não muda com base na orientação, etc.)." Isso praticamente diz que você não deveria fazer isso, mesmo que de alguma forma funcione.
Austyn Mahoney
Acabei de ler o comentário do @ AustynMahoney e percebi que essa resposta não é tão boa quanto eu pensava, mas SO não vai me deixar desfazer o meu voto ! Argh!
Vicky Chijwani
45

Para DP to Pixel

Crie um valor em dimens.xml

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

Obtenha esse valor pixelcomo:

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

Portanto, você pode usar o formulador a seguir para calcular a quantidade correta de pixels de uma dimensão especificada em 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
fonte
4
Isso converte dp em pixels, mas você chamou seu método convertToDp.
Qwertie
4
+ 0.5f é explicado aqui -> developer.android.com/guide/practices/… . É usado para arredondar para o número inteiro mais próximo.
Bae
a única resposta certa. você pode adicionar o código-fonte developer.android.com/guide/practices/…
user25 28/08
web.archive.org/web/20140808234241/http://developer.android.com/… para um link que ainda tem o conteúdo em questão
caw
39

Para quem usa o 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
fonte
Nos documentos de Resource.getSystem (): "Retorne um objeto Global compartilhado de Recursos que fornece acesso apenas aos recursos do sistema (sem recursos do aplicativo) e não está configurado para a tela atual (não pode usar unidades de dimensão, não muda com base em orientação etc.) ".
precisa saber é o seguinte
@HendraWD Os documentos podem ser confusos, as unidades de dimensão mencionadas são o nível de seu aplicativo que diminui os recursos. displayMetrics não é um recurso no nível do aplicativo. É um recurso do sistema e retorna os valores corretos. Este código está funcionando bem em todos os meus aplicativos Prod. Nunca tive um problema.
Gunhan
33

Há um utilitário padrão no SDK do Android: http://developer.android.com/reference/android/util/TypedValue.html

float resultPix = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
Kvant
fonte
Você deveria estar usando este. Como bônus, ele também fará SP.
Marque 'Renouf
2
resultPixdeve ser do tipo int. int resultPix = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())
vovahost
27

usando o kotlin-extension torna melhor

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

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

ATUALIZAR:

Como displayMetricsfaz parte dos Recursos compartilhados globais , podemos usarResources.getSystem()

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

fun Int.toDp(): Int = (this / Resources.getSystem().displayMetrics.density).toInt()
beigirad
fonte
4
Por que você o adicionaria como uma extensão do Int, a responsabilidade não precisa fazer nada com o tipo Int.
Htafoya 30/10/19
19

Isso deve fornecer a conversão dp para pixels:

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

Isso deve fornecer os pixels de conversão para dp:

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

Provavelmente, a melhor maneira de obter a dimensão dentro de values ​​/ dimen é obtendo a dimensão diretamente do método getDimension (), ela retornará a dimensão já convertida em valor de pixel.

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

Apenas para explicar melhor isso,

getDimension(int resourceId) 

retornará a dimensão já convertida em pixel AS A FLOAT.

getDimensionPixelSize(int resourceId)

retornará o mesmo, mas truncado para int, portanto AS INTEGER.

Consulte referência Android

Lorenzo Barbagli
fonte
9
Para converter dp em pixel.
public static int dp2px(Resources resource, int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,   dp,resource.getDisplayMetrics());
}
Para converter pixel em dp.
  public static float px2dp(Resources resource, float px)  {
    return (float) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,resource.getDisplayMetrics());
}

onde o recurso é context.getResources ().

Prince Gupta
fonte
8
A resposta está errada, porque você não está convertendo pixels em dp - você está convertendo pixels em pixels!
Yaroslav
O px2dp está errado - retornará o mesmo valor em pixels.
Natario #
8

como isso:

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

dependente do contexto, retornar valor flutuante, método estático

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

Trinea
fonte
8

Abordagem mais elegante usando a função de extensão do 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
fonte
Adoro o uso da extensão aqui. Eu li as funções como "converter para function name", que eu percebo que estão ao contrário neste caso. Para esclarecer a intenção de cada função, os nomes das funções podem ser atualizados para ler dpToPx e pxToDp, respectivamente.
Maxwell
Nos documentos de Resource.getSystem (): "Retorne um objeto Global compartilhado de Recursos que fornece acesso apenas aos recursos do sistema (sem recursos do aplicativo) e não está configurado para a tela atual (não pode usar unidades de dimensão, não muda com base em orientação etc.) ".
precisa saber é o seguinte
7
float scaleValue = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scaleValue + 0.5f);
Sibin
fonte
2
Não é o mesmo que está coberto em muitas das outras respostas a esta pergunta?
TZHX
7

Caso esteja desenvolvendo um aplicativo crítico de desempenho, considere a seguinte classe otimizada:

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
fonte
Só faz sentido se você fizer conversões com muita frequência. No meu caso eu faço.
Pavel
O que é 160f? Por que você usa, por que é 160?
dephinera
160 => 160dpi e isto é para medidas de conversão, porque de fórmula
xAqweRx
6

para converter pixels em dp, use o TypedValue .

Conforme a documentação mencionada: Contêiner para um valor de dados digitado dinamicamente.

e use o método applyDimension :

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

que Converte um valor de dados complexos descompactado, mantendo uma dimensão em seu valor final de ponto flutuante, como o seguinte:

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

Espero que ajude .


fonte
6

É assim que funciona para mim:

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

Você pode fazer o mesmo para a largura.

Temi Mide Adey
fonte
4

Você deve usar o dp como faria com os pixels. Isso é tudo o que são; exibir pixels independentes. Use os mesmos números que você usaria em uma tela de densidade média e o tamanho estará magicamente correto em uma tela de alta densidade.

No entanto, parece que você precisa da opção fill_parent no seu design de layout. Use fill_parent quando desejar que sua visualização ou controle se expanda para todo o tamanho restante no contêiner pai.

Michael Lowman
fonte
na verdade, o meu problema é o meu pedido é codificado para a tela de alta densidade e agora ele precisa ser convertido para a tela de baixa densidade ..
Indhu
modifique seus pixels para uma tela de densidade média (você pode configurar uma tela de densidade média no emulador) e substitua o pixel por dp. No entanto, aplicativos mais flexíveis podem ser feitos usando fill_parent e vários layouts.
Michael Lowman
Finalmente, eu não tinha opção a não ser alterar manualmente todos os px para dp .. :(
Indhu
1
Pelo menos da próxima vez, você usará o dp primeiro e não precisará alterar nada :) Embora seja possível usar layouts que não exijam posicionamento absoluto para a maioria das coisas.
Michael Lowman
Desde que foi o meu primeiro aplicativo .. eu cometi esse erro ... eu nunca vou fazê-lo novamente ... :) #
314 Indhu
4

PXe DPsão diferentes, mas semelhantes.

DPé a resolução quando você considera apenas o tamanho físico da tela. Ao usá- DPlo, o layout será dimensionado para outras telas de tamanhos semelhantes com pixeldensidades diferentes .

Ocasionalmente, você realmente deseja pixels, e quando lida com dimensões no código, está sempre lidando com real pixels, a menos que as converta.

Então, em um dispositivo Android, hdpitela de tamanho normal , 800x480 is 533x320em DP(eu acredito). Para converter DPem pixels /1.5, para converter de volta *1.5. Isso é apenas para o tamanho de uma tela e dpiisso mudaria dependendo do design. pixelsPorém, nossos artistas me deram e eu me converti DPcom a 1.5equação acima .

HaMMeReD
fonte
3

Se você deseja valores inteiros , usar Math.round () arredondará o valor flutuante para o número inteiro mais próximo.

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

A melhor resposta vem da própria estrutura do Android: basta usar essa igualdade ...

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

(converte dp em px)

JarsOfJam-Scheduler
fonte
2

Isso funciona para mim (C #):

int pixels = (int)((dp) * Resources.System.DisplayMetrics.Density + 0.5f);
Michael Zhang
fonte
Não é uma resposta para esta pergunta, mas para o C # funciona. Obrigado
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
fonte