web-dev-qa-db-fra.com

Pourquoi mon vecteur ne peut-il pas être mis à l'échelle comme prévu?

J'essaie d'utiliser des éléments vectoriels dans mon application Android. De http://developer.Android.com/training/material/drawables.html (c'est moi qui souligne):

Dans Android 5.0 (API niveau 21) et les versions ultérieures, vous pouvez définir des vecteurs dessinables, qui sont redimensionnés sans perdre la définition.

En utilisant ce dessinable:

<vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:height="24dp"
Android:width="24dp"
Android:viewportWidth="24"
Android:viewportHeight="24">
<path Android:fillColor="@color/colorPrimary" Android:pathData="M14,20A2,2 0 0,1 12,22A2,2 0 0,1 10,20H14M12,2A1,1 0 0,1 13,3V4.08C15.84,4.56 18,7.03 18,10V16L21,19H3L6,16V10C6,7.03 8.16,4.56 11,4.08V3A1,1 0 0,1 12,2Z" />

et cette ImageView:

<ImageView
    Android:layout_width="400dp"
    Android:layout_height="400dp"
    Android:src="@drawable/icon_bell"/>

produit cette image floue lorsqu’on essaie d’afficher l’icône à 400dp (sur un appareil mobile de haute résolution vers 2015 fonctionnant sous Lollipop):

blurryBellIcon

Changer la largeur et la hauteur dans la définition du vecteur dessiné à 200dp améliore considérablement la situation à la taille de rendu de 400dp. Cependant, définir ceci comme dessinable pour un élément TextView (c'est-à-dire une icône à gauche du texte) crée désormais une énorme icône.

Mes questions:

1) Pourquoi y-a-t-il une spécification largeur/hauteur dans le vecteur dessinable? Je pensais que le but de tout cela était qu’ils s’échelonnent sans perte, ce qui rend la largeur et la hauteur sans signification dans sa définition.

2) Est-il possible d’utiliser un seul vecteur pouvant être dessiné, qui fonctionne comme un dessin de 24dp sur un TextView, mais dont l’échelle permet également d’utiliser des images beaucoup plus grandes? Par exemple. Comment puis-je éviter de créer plusieurs vecteurs dessinables de tailles différentes et d’en utiliser un qui s'adapte à mes besoins de rendu?

3) Comment utiliser efficacement les attributs width/height et quelle est la différence avec viewportWidth/Height?

Détails supplémentaires:

  • Le périphérique exécute l'API 22
  • Utilisation de Android Studio v1.5.1 avec Gradle version 1.5.0
  • Manifest est compilé et cible au niveau 23, niveau minimum 15. J'ai également essayé de déplacer le niveau minimum à 21, mais cela ne faisait aucune différence.
  • La décompilation de l'APK (avec le niveau minimum défini sur 21) affiche une seule ressource XML dans le dossier pouvant être dessiné. Aucune image pixellisée n'est produite.
83
Chris Knight

Il y a de nouvelles informations sur ce problème ici:

https://code.google.com/p/Android/issues/detail?id=202019

Il semble que l'utilisation de Android:scaleType="fitXY" le fasse évoluer correctement sur Lollipop.

D'un ingénieur Google:

Bonjour, Indiquez-moi si scaleType = 'fitXY' peut être une solution de contournement pour vous, afin de rendre l'image plus nette.

Le Marshmallow Vs Lollipop est dû à un traitement spécial de détartrage ajouté à Marshmallow.

En outre, pour vos commentaires: "Comportement correct: le vecteur dessinable doit évoluer sans perte de qualité. Donc, si nous souhaitons utiliser le même actif dans 3 tailles différentes dans notre application, nous n’avons pas à dupliquer vector_drawable.xml 3 fois avec des tailles codées en dur. "

Bien que je sois tout à fait d’accord sur ce point, en réalité, la plate-forme Android présente des problèmes de performances tels que nous n’avons pas encore atteint le monde idéal. Il est donc recommandé d’utiliser 3 fichiers vector_drawable.xml différents pour de meilleures performances si vous êtes certain de vouloir dessiner 3 tailles différentes sur l’écran en même temps.

Le détail technique consiste essentiellement à utiliser une image bitmap sous le crochet pour mettre en cache le rendu du chemin complexe, de manière à obtenir les meilleures performances de redessinage, à égalité avec le redessinage d'un bitmap dessinable.

91
Taehyun Park

1) Pourquoi y-a-t-il une spécification largeur/hauteur dans le vecteur dessinable? Je pensais que le but de tout cela était qu’ils s’échelonnent sans perte, ce qui rend la largeur et la hauteur sans signification dans sa définition.

Pour les versions de SDK inférieures à 21, le système de génération doit générer des images raster et est la taille par défaut lorsque vous ne spécifiez pas la largeur/hauteur.

2) Est-il possible d’utiliser un seul vecteur pouvant être dessiné, qui fonctionne comme un dessin de 24dp sur un TextView, ainsi qu’une grande image de largeur proche de l’écran?

Je ne crois pas que cela soit possible si vous devez également cibler les SDK de moins de 21 ans.

3) Comment utiliser efficacement les attributs width/height et quelle est la différence avec viewportWidth/Height?

Documentation: (en fait pas très utile maintenant que je le relis ...)

Android:width

Utilisé pour définir la largeur intrinsèque du dessinable. Ceci supporte toutes les unités de dimension, spécifiées normalement avec dp.

Android:height

Utilisé pour définir la hauteur intrinsèque du dessinable. Ceci supporte toutes les unités de dimension, spécifiées normalement avec dp.

Android:viewportWidth

Utilisé pour définir la largeur de l'espace de la fenêtre. Viewport est essentiellement le canevas virtuel sur lequel les chemins sont dessinés.

Android:viewportHeight

Utilisé pour définir la hauteur de l'espace de la fenêtre. Viewport est essentiellement le canevas virtuel sur lequel les chemins sont dessinés.

Plus de documentation:

Android 4.4 (API de niveau 20) et inférieur ne prend pas en charge les dessins vectoriels. Si votre niveau d'API minimum est défini sur l'un de ces niveaux, Vector Asset Studio demande également à Gradle de générer des images raster du vecteur pouvant être dessiné pour assurer la compatibilité avec les versions antérieures. Vous pouvez faire référence aux ressources vectorielles sous la forme Drawable dans Java code ou @drawable dans le code XML; Lorsque votre application est exécutée, l'image vectorielle ou raster correspondante s'affiche automatiquement en fonction du niveau de l'API.


Edit: Quelque chose de bizarre se passe. Voici mes résultats dans l'émulateur SDK version 23 (le périphérique de test Lollipop + est mort en ce moment ...):

Good bells on 6.x

Et dans l'émulateur SDK version 21:

Crappy bells on 5.x

25
Cory Charlton

AppCompat 23.2 introduit les dessins vectoriels pour tous les appareils exécutant Android 2.1 et versions ultérieures. Les images sont correctement redimensionnées, indépendamment de la largeur/hauteur spécifiée dans le fichier XML du dessin. Malheureusement, cette implémentation n'est pas utilisée dans les API de niveau 21 et supérieur (en faveur de l'implémentation native).

La bonne nouvelle est que nous pouvons forcer AppCompat à utiliser son implémentation aux niveaux 21 et 22 de l'API. La mauvaise nouvelle est que nous devons utiliser la réflexion pour le faire.

Tout d'abord, assurez-vous que vous utilisez la dernière version d'AppCompat et que vous avez activé la nouvelle implémentation vectorielle:

Android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
    compile 'com.Android.support:appcompat-v7:23.2.0'
}

Ensuite, appelez useCompatVectorIfNeeded(); dans la fonction onCreate () de votre application:

private void useCompatVectorIfNeeded() {
    int sdkInt = Build.VERSION.SDK_INT;
    if (sdkInt == 21 || sdkInt == 22) { //vector drawables scale correctly in API level 23
        try {
            AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
            Class<?> inflateDelegateClass = Class.forName("Android.support.v7.widget.AppCompatDrawableManager$InflateDelegate");
            Class<?> vdcInflateDelegateClass = Class.forName("Android.support.v7.widget.AppCompatDrawableManager$VdcInflateDelegate");

            Constructor<?> constructor = vdcInflateDelegateClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            Object vdcInflateDelegate = constructor.newInstance();

            Class<?> args[] = {String.class, inflateDelegateClass};
            Method addDelegate = AppCompatDrawableManager.class.getDeclaredMethod("addDelegate", args);
            addDelegate.setAccessible(true);
            addDelegate.invoke(drawableManager, "vector", vdcInflateDelegate);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

Enfin, assurez-vous que vous utilisez app:srcCompat au lieu de Android:src pour définir l'image de votre ImageView:

<ImageView
    Android:layout_width="400dp"
    Android:layout_height="400dp"
    app:srcCompat="@drawable/icon_bell"/>

Votre dessin vectoriel devrait maintenant s'ajuster correctement!

9
user3210008

1) Pourquoi y-a-t-il une spécification largeur/hauteur dans le vecteur dessinable? Je pensais que le but de tout cela était qu’ils s’échelonnent sans perte, ce qui rend la largeur et la hauteur sans signification dans sa définition.

Ceci est simplement la taille par défaut du vecteur au cas où vous ne le définissez pas en mode Mise en page. (c.-à-d. que vous utilisez un contenu enveloppant pour la hauteur et la largeur de votre imageview)

2) Est-il possible d’utiliser un seul vecteur pouvant être dessiné, qui fonctionne comme un dessin de 24dp sur un TextView, ainsi qu’une grande image de largeur proche de l’écran?

Oui, c'est possible et je n'ai eu aucun problème de redimensionnement tant que le périphérique en cours d'utilisation utilise Lollipop ou une version ultérieure. Dans les API précédentes, le vecteur est converti en pngs pour différentes tailles d'écran lorsque vous créez l'application.

3) Comment utiliser efficacement les attributs width/height et quelle est la différence avec viewportWidth/Height?

Cela affecte la manière dont l'espace autour de votre vecteur est utilisé. Cela signifie que vous pouvez l'utiliser pour modifier la "gravité" du vecteur dans la fenêtre, lui donner une marge par défaut, laisser certaines parties du vecteur en dehors de la fenêtre, etc ... Normalement, il vous suffit de les définir Taille.

6
emirua

J'essaie de ces façons mais malheureusement, aucune d'entre elles n'a fonctionné. J'essaie fitXY dans ImageView, j'essaie d'utiliser app:srcCompat mais je ne peux même pas l'utiliser. mais j'ai trouvé un truc:

réglez Drawable sur background de votre ImageView.

Mais l’intérêt de cette méthode est la dimension Vues. si votre ImageView a des dimensions incorrectes, drawable obtient Stretch. vous devez le contrôler dans les versions antérieures à Lollipop ou utiliser certaines vues PercentRelativeLayout.

J'espère que c'est utile.

3
Mahdi Astanei

Premier : importer un svg vers drawble: (( https://www.learn2crack.com/2016/02/Android-studio-svg) .html ))

1-Faites un clic droit sur le dossier pouvant être dessiné, sélectionnez Nouveau -> Image vectorielle

enter image description here

2- Vector Asset Studio vous permet de sélectionner les icônes de matériau intégrées ou votre propre fichier svg local. Vous pouvez remplacer la taille par défaut si nécessaire.

enter image description here

Deuxième : si vous souhaitez que Android API 7+ soit supporté, vous devez utiliser Android Enregistrement de la bibliothèque de support (( https://stackoverflow.com/a/44713221/1140304 ))

1- ajouter

vectorDrawables.useSupportLibrary = true

dans votre fichier build.gradle.

2-Utilisez un espace de noms dans votre mise en page avec imageView:

xmlns:app="http://schemas.Android.com/apk/res-auto"

Troisième : définissez imageView avec Android: scaleType = "fitXY" et utilisez l'application: srcCompat

 <ImageView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:scaleType="fitXY"
        app:srcCompat="@drawable/ic_menu" />

Quatrième : si vous voulez définir svg dans le code Java, vous devez ajouter la ligne ci-dessous sur oncreate methoed

 @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
2
MiladAhmadi

Je résous mon problème il suffit de changer la taille de l'image vectorielle. Dès le début c'était une ressource comme:

<vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:aapt="http://schemas.Android.com/aapt"
    Android:width="24dp"
    Android:height="24dp"
    Android:viewportHeight="300"
    Android:viewportWidth="300">

Et je l'ai changé à 150dp (taille de ImageView dans la présentation avec cette ressource vectorielle) comme:

<vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:aapt="http://schemas.Android.com/aapt"
    Android:width="150dp"
    Android:height="150dp"
    Android:viewportHeight="300"
    Android:viewportWidth="300">

Cela fonctionne pour moi.

1
Djek-Grif

Pour moi, la raison pour laquelle les vecteurs ont été convertis en png était l'attribut Android:fillType="evenodd" dans mon vecteur drawable. Lorsque je supprime toutes les occurrences de cet attribut dans mon dessinable (ainsi le vecteur utilisant le type de remplissage nonzero par défaut), la prochaine fois que l'application est construite, tout va bien.

0
Mahozad