Como centralizar o drawable vetorial na lista de camadas sem escalar


102

Estou tentando usar a VectorDrawableem a LayerListsem dimensionar o vetor. Por exemplo:

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
    <item android:gravity="center" android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

O ic_check_white_48dpid de drawable definido como:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#FFFFFFFF"
        android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

O efeito desejado é que o ícone de verificação seja centralizado no drawable da camada, sem escala. O problema é que a lista de camadas acima faz com que o ícone de verificação seja dimensionado para caber no tamanho da camada.

I pode produzir o efeito desejado se eu substituir o vector amovível com PNGs para cada densidade e modificar a lista de camada tais como:

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
    <item>
        <bitmap android:gravity="center" android:src="@drawable/ic_check_white_48dp"/>
    </item>
</layer-list>

Existe alguma maneira de fazer isso usando um VectorDrawable?


11
Parece que isso pode ser simplesmente um bug na API 21/22. Acabei de testar em um dispositivo API 23 e o drawable vetorial foi centralizado corretamente.
ashughes de

1
Você deve responder à sua própria pergunta e aceitá-la. Assim fica mais visível e a pergunta não aparece como sem resposta.
Marcin Koziński

1
Não respondi minha pergunta porque ainda não tenho uma resposta sobre o que fazer na API 21/22. Minha solução temporária foi usar PNGs em vez de vetores. Esperando ainda encontrar uma maneira de fazer os vetores funcionarem.
ashughes de


Isso já foi corrigido na API 23, então suponho que seu relatório de bug será apenas marcado como corrigido.
ashughes

Respostas:


29

Eu tive o mesmo problema ao tentar centralizar drawables de vetores em uma lista em camadas.

Eu tenho uma solução alternativa, não é exatamente o mesmo, mas funciona, você precisa definir um tamanho para todo o drawable e adicionar preenchimento ao item de vetor:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <size android:height="120dp" android:width="120dp"/>
            <solid android:color="@color/grid_item_activated"/>
        </shape>
    </item>
    <item android:top="24dp"
          android:bottom="24dp"
          android:left="24dp"
          android:right="24dp"
          android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

O tamanho da forma acima define o tamanho de todo o drawable, 120 dp neste exemplo, o preenchimento no segundo item, 24 dp neste exemplo, centraliza a imagem vetorial.

Não é o mesmo que usar o, gravity="center"mas é a maneira de trabalhar de usar vetores na API 21 e 22.


2
Isso parece exigir que você saiba o tamanho exato do drawable (a fim de definir o tamanho da forma), em vez de permitir que ele preencha todo o espaço definido com o drawable de cheque centralizado nele.
ashughes

1
é possível não saber o tamanho, mas você não pode alterar o preenchimento com este método, você pode colocar os drawables em cima uns dos outros em visualizações de imagens. Como afirmei acima, não há solução perfeita para um gravity="center"em API 21 e 22.
Nicolas Tyler

Não funciona quando usado com windowBackground. Os tamanhos explícitos não fazem nada neste caso. E também não funciona se eu colocar a lista de camadas dentro de outra lista de camadas.
Vsevolod Ganin

19

Tenho lutado com o mesmo problema. A única maneira que encontrei de corrigir isso e evitar que o drawable aumentasse a escala foi definir o tamanho do drawable e usar a gravidade para alinhá-lo:

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
     <item
        android:gravity="center"
        android:width="48dp"
        android:height="48dp"
        android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

Espero que ajude!


34
Isso não ajuda na API 21-22, porque o widthatributo não está disponível nesses níveis de API. Na API 23, eles não são necessários, porque o bug foi corrigido e o drawable não é mais alongado.
WonderCsabo

3
Isso não funciona corretamente para API 27, a imagem é esticada para tela
inteira

8

Solução editada que fará com que seu SplashScreen tenha uma ótima aparência em todas as APIs, incluindo API21 a API23

Antes de mais nada leia este artigo e siga a BOA maneira de fazer uma tela inicial.

Se o seu logotipo estiver distorcido ou não couber e você está direcionando apenas para APIs24 +, você pode simplesmente reduzir seu drawable vetorial diretamente em seu arquivo xml assim:

<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="640"
android:viewportHeight="640"
android:width="240dp"
android:height="240dp">
<path
    android:pathData="M320.96 55.9L477.14 345L161.67 345L320.96 55.9Z"
    android:strokeColor="#292929"
    android:strokeWidth="24" />
</vector>

no código acima, estou redimensionando um drawable que desenhei em uma tela de 640x640 para 240x240. em seguida, coloco-o no drawable da tela inicial e funciona muito bem:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"
android:paddingBottom="20dp" android:paddingRight="20dp" android:paddingLeft="20dp" android:paddingTop="20dp">

<!-- The background color, preferably the same as your normal theme -->
<item>
    <shape>
        <size android:height="120dp" android:width="120dp"/>
        <solid android:color="@android:color/white"/>
    </shape>
</item>

<!-- Your product logo - 144dp color version of your app icon -->
<item
    android:drawable="@drawable/logo_vect"
    android:gravity="center">

</item>
</layer-list>

meu código está, na verdade, apenas desenhando o triângulo na imagem na parte inferior, mas aqui você vê o que pode fazer com isso. A resolução finalmente é ótima, ao contrário das bordas pixeladas que recebia ao usar bitmap. portanto, use um drawable vetorial por todos os meios (há um site chamado vectr que usei para criar o meu sem o incômodo de baixar um software especializado).

EDITAR para que funcione também na API21-22-23

Embora a solução acima funcione para dispositivos que executam API24 +, fiquei muito desapontado depois de instalar meu aplicativo em um dispositivo que executam API22. Notei que a tela inicial estava novamente tentando preencher a visão inteira e parecendo uma merda. Depois de arrancar minhas sobrancelhas por meio dia, finalmente forcei brutalmente uma solução por pura força de vontade.

você precisa criar um segundo arquivo nomeado exatamente como o xml splashscreen (digamos splash_screen.xml) e colocá-lo em 2 pastas chamadas drawable-v22 e drawable-v21 que você criará na pasta res / (para vê-los você tem que mudar sua visão do projeto de Android para Projeto). Isso serve para instruir seu telefone a redirecionar para arquivos colocados nessas pastas sempre que o dispositivo relevante executar uma API correspondente ao sufixo -vXX na pasta drawable, consulte este link . coloque o seguinte código na lista de camadas do arquivo splash_screen.xml que você cria nestas pastas:

<item>
<shape>
    <size android:height="120dp" android:width="120dp"/>
    <solid android:color="@android:color/white"/>
</shape>
</item>

<!-- Your product logo - 144dp color version of your app icon -->
<item android:gravity="center">
    <bitmap android:gravity="center"
        android:src="logo_vect"/>

</item>

esta é a aparência das pastas

Por alguma razão para essas APIs, você precisa envolver seu drawable em um bitmap para fazê-lo funcionar e fazer com que o resultado final pareça o mesmo. O problema é que você deve usar a abordagem com as pastas adicionais de drawable, pois a segunda versão do arquivo splash_screen.xml fará com que sua tela inicial não seja exibida em dispositivos que executam APIs superiores a 23. Você também pode ter que colocar a primeira versão do splash_screen.xml em drawable-v24 como padrão do Android para a pasta drawable-vXX mais próxima que ele pode encontrar para recursos.

minha tela inicial


4

Atualmente, estou trabalhando em uma tela inicial com um drawable vetorial centralizado horizontal e verticalmente. Aqui está o que eu obtive no nível 25 da API:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">

<!-- background color, same as theme -->
<item android:drawable="@android:color/white"/>

<!-- app logo -->

<item
    android:drawable="@drawable/my_app_logo"
    android:gravity="center_horizontal|center_vertical"
    android:width="200dp"
    android:height="200dp"
    />
</layer-list>

Se você quiser ajustar a dimensão do drawable vetorial, modifique android:widtheandroid:height atributos acima, não necessariamente modifique o drawable original.

Além disso, minha experiência é NÃO coloque o drawable vetorial em uma tag de bitmap, o que nunca funciona para mim. Bitmap é para arquivos de formato .png, .jpg e .gif, não para drawable vetorial.

Referência

https://developer.android.com/guide/topics/resources/drawable-resource#LayerList

https://developer.android.com/guide/topics/resources/more-resources.html#Dimension


1
Uma boa ideia sobre drawables vetoriais que precisam estar dentro de uma tag <item> em vez de uma tag <bitmap>.
FrostRocket
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.