Comment centrer un vecteur dessinable dans une liste de calques sans mise à l'échelle

102

J'essaie d'utiliser un VectorDrawabledans un LayerListsans mettre à l'échelle le vecteur. Par exemple:

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

L' ic_check_white_48dpidentifiant drawable défini comme:

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

L'effet souhaité est que l'icône de coche soit centrée dans le calque dessinable, sans mise à l'échelle. Le problème est que la liste des calques ci-dessus entraîne la mise à l'échelle de l'icône de vérification pour s'adapter à la taille du calque.

Je peux produire l'effet souhaité si je remplace le vecteur dessiné par des PNG pour chaque densité et que je modifie la liste des calques en tant que telle:

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

Est-il possible de faire cela en utilisant un VectorDrawable?

ashughes
la source
11
Il semble qu'il s'agisse simplement d'un bogue dans l'API 21/22. Je viens de tester sur un appareil API 23 et le dessin vectoriel était correctement centré.
ashughes
1
Vous devez répondre à votre propre question et l'accepter. De cette façon, il est plus visible et la question n'apparaît pas comme sans réponse.
Marcin Koziński
1
Je n'ai pas répondu à ma question car je n'ai pas encore de réponse sur ce qu'il faut faire sur l'API 21/22. Ma solution temporaire était d'utiliser des PNG au lieu de vecteurs. En espérant encore trouver un moyen de faire fonctionner les vecteurs.
ashughes
1
J'ai ouvert un problème ici: code.google.com/p/android/issues/detail?id=219600
toobsco42
Ceci est déjà corrigé dans l'API 23, donc je suppose que votre rapport de bogue sera simplement marqué comme corrigé.
ashughes

Réponses:

29

J'ai rencontré le même problème en essayant de centrer les vecteurs drawables sur une liste en couches.

J'ai une solution de contournement, ce n'est pas exactement la même chose mais cela fonctionne, vous devez définir une taille pour l'ensemble du dessinable et ajouter un rembourrage à l'élément vectoriel:

<?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>

La taille de la forme ci-dessus définit la taille de l'ensemble du dessinable, 120dp dans cet exemple, le remplissage sur le deuxième élément, 24dp dans cet exemple, centre l'image vectorielle.

Ce n'est pas la même chose que d'utiliser le gravity="center"mais sa façon de travailler d'utiliser les vecteurs dans l'API 21 et 22.

Nicolas Tyler
la source
2
Cela semble vous obliger à connaître la taille exacte du dessinable (afin de définir la taille de la forme), plutôt que de le laisser remplir tout l'espace sur lequel il est défini avec le chèque dessiné au centre.
ashughes le
1
il est possible de ne pas connaître la taille mais vous ne pouvez pas changer le remplissage avec cette méthode, vous pouvez superposer les drawables les uns sur les autres dans les vues d'image. Comme je l'ai dit ci-dessus, il n'y a pas de solution parfaite pour un gravity="center"API 21 et 22.
Nicolas Tyler
Cela ne fonctionne pas lors de l'utilisation avec windowBackground. Les tailles explicites ne font rien dans ce cas. Et cela ne fonctionne pas non plus si je mets la liste de couches dans une autre liste de couches.
Vsevolod Ganin
19

J'ai été aux prises avec le même problème. Le seul moyen que j'ai trouvé pour résoudre ce problème et éviter que le dessin ne soit mis à l'échelle était de définir la taille du dessin et d'utiliser la gravité pour l'aligner:

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

J'espère que ça aide!

Felipe Duarte
la source
34
Cela n'aide pas sur l'API 21-22, car l' widthattribut n'est pas disponible sur ces niveaux d'API. Sur l'API 23, ceux-ci ne sont pas nécessaires, car le bogue est corrigé et le dessin n'est plus étiré.
WonderCsabo
3
Cela ne fonctionne pas correctement pour l'API 27, l'image est étirée en plein écran
Konstantin Konopko
8

Solution modifiée qui donnera à votre SplashScreen une belle apparence sur toutes les API, y compris API21 à API23

Tout d'abord, lisez cet article et suivez la BONNE façon de créer un écran de démarrage.

Si votre logo est déformé ou ne convient pas et que vous ciblez uniquement les API24 +, vous pouvez simplement réduire votre vecteur dessiné directement dans son fichier xml comme ceci:

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

dans le code ci-dessus, je redimensionne un dessinable que j'ai dessiné sur une toile 640x640 pour être 240x240. alors je viens de le mettre dans mon écran de démarrage dessiné comme ça et cela fonctionne très bien:

<?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>

mon code ne dessine en fait que le triangle dans l'image en bas, mais ici vous voyez ce que vous pouvez réaliser avec cela. La résolution est enfin excellente par rapport aux bords pixélisés que j'obtenais lors de l'utilisation de bitmap. alors utilisez un vecteur dessinable par tous les moyens (il existe un site appelé vectr que j'ai utilisé pour créer le mien sans avoir à télécharger un logiciel spécialisé).

EDIT afin de le faire fonctionner également sur API21-22-23

Bien que la solution ci-dessus fonctionne pour les appareils exécutant API24 +, j'ai été vraiment déçu après avoir installé mon application sur un appareil exécutant API22. J'ai remarqué que l'écran de démarrage essayait à nouveau de remplir la vue entière et ressemblait à de la merde. Après avoir arraché mes sourcils pendant une demi-journée, j'ai finalement forcé brutalement une solution par pure volonté.

vous devez créer un deuxième fichier nommé exactement comme le splashscreen xml (disons splash_screen.xml) et le placer dans 2 dossiers appelés drawable-v22 et drawable-v21 que vous créerez dans le dossier res / (pour les voir, vous devez changer la vue de votre projet d'Android en Projet). Cela sert à dire à votre téléphone de rediriger vers les fichiers placés dans ces dossiers chaque fois que l'appareil concerné exécute une API correspondant au suffixe -vXX dans le dossier pouvant être dessiné, voir ce lien . placez le code suivant dans la liste des couches du fichier splash_screen.xml que vous créez dans ces dossiers:

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

voici à quoi ressemblent les dossiers

Pour une raison quelconque pour ces API, vous devez envelopper votre dessinable dans un bitmap afin de le faire fonctionner et de donner le même résultat au résultat final. Le problème est que vous devez utiliser l'approche avec les dossiers dessinables supplémentaires car la deuxième version du fichier splash_screen.xml entraînera que votre écran de démarrage ne s'affiche pas du tout sur les appareils exécutant des API supérieures à 23. Vous devrez peut-être également placer la première version de splash_screen.xml dans drawable-v24 car Android utilise par défaut le dossier drawable-vXX le plus proche qu'il peut trouver pour les ressources.

mon écran de démarrage

quealegriamasalegre
la source
4

Je travaille actuellement sur un écran de démarrage avec un dessin vectoriel centré à la fois horizontalement et verticalement. Voici ce que j'ai obtenu au niveau de l'API 25:

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

Si vous souhaitez ajuster la dimension du dessin vectoriel, les modifier android:widthet les android:heightattributs ci-dessus, ne modifiez pas nécessairement le dessinable d'origine.

De plus, mon expérience est de NE PAS mettre le vecteur dessinable dans une balise bitmap, ce qui ne fonctionne jamais pour moi. Bitmap est destiné aux fichiers au format .png, .jpg et .gif, pas aux fichiers vectoriels.

Référence

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

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

Wenhe Qi
la source
1
Bonne prise à propos des dessins vectoriels devant être dans une balise <item> au lieu d'une balise <bitmap>.
FrostRocket