Come centrare il vettore disegnabile nell'elenco dei livelli senza ridimensionamento


102

Sto tentando di utilizzare a VectorDrawablein a LayerListsenza ridimensionare il vettore. Per esempio:

<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_48dpID disegnabile definito come:

<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'effetto desiderato è che l'icona di spunta sia centrata nel livello disegnabile, senza ridimensionamento. Il problema è che l'elenco dei livelli in alto fa sì che l'icona di controllo venga ridimensionata per adattarsi alle dimensioni del livello.

Io posso produrre l'effetto desiderato se si sostituisce la drawable vettore con PNGs per ogni densità e modificare lo strato lista come tale:

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

C'è un modo per farlo usando un VectorDrawable?


11
Sembra che questo possa essere semplicemente un bug nell'API 21/22. Ho appena testato su un dispositivo API 23 e il disegno vettoriale era centrato correttamente.
Ashughes

1
Dovresti rispondere alla tua domanda e accettarla. In questo modo è più visibile e la domanda non appare come senza risposta.
Marcin Koziński

1
Non ho risposto alla mia domanda perché non ho ancora una risposta su cosa fare su API 21/22. La mia soluzione temporanea era utilizzare PNG invece di vettori. Sperando comunque di trovare un modo per far funzionare i vettori.
ashughes


Questo problema è già stato risolto nell'API 23, quindi immagino che la tua segnalazione di bug verrà contrassegnata come corretta.
Ashughes il

Risposte:


29

Mi sono imbattuto nello stesso problema cercando di centrare i vettori disegnabili su un elenco a strati.

Ho una soluzione alternativa, non è esattamente la stessa ma funziona, devi impostare una dimensione per l'intero disegnabile e aggiungere il riempimento all'elemento vettoriale:

<?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 dimensione della forma sopra imposta la dimensione dell'intero disegnabile, 120dp in questo esempio, il riempimento sul secondo elemento, 24dp in questo esempio, centra l'immagine vettoriale.

Non è la stessa cosa che usare gravity="center"ma il suo modo di usare i vettori nelle API 21 e 22.


2
Questo suona come richiederebbe che tu conosca la dimensione esatta del disegnabile (per impostare la dimensione della forma), piuttosto che lasciarlo riempire l'intero spazio su cui è impostato con il controllo disegnabile centrato al suo interno.
Ashughes

1
è possibile non conoscere la dimensione ma non è possibile modificare il riempimento con questo metodo, è possibile sovrapporre i drawables uno sopra l'altro nelle visualizzazioni di immagini. Come ho detto sopra, non esiste una soluzione perfetta per gravity="center"API 21 e 22.
Nicolas Tyler

Non funziona quando si utilizza con windowBackground. Le dimensioni esplicite non fanno nulla in questo caso. E non funziona neanche se inserisco l'elenco dei livelli all'interno di un altro elenco dei livelli.
Vsevolod Ganin

19

Ho lottato con lo stesso problema. L'unico modo che ho trovato per risolvere questo problema ed evitare che il disegnabile si ridimensionasse era impostare la dimensione del disegno e usare la gravità per allinearlo:

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

Spero che sia d'aiuto!


34
Questo non aiuta su API 21-22, perché l' widthattributo non è disponibile su quei livelli API. Su API 23, questi non sono necessari, perché il bug è stato corretto e il disegnabile non è più allungato.
WonderCsabo

3
Questo non funziona correttamente per API 27, l'immagine è allungata a schermo intero
Konstantin Konopko

8

Soluzione modificata che renderà il tuo SplashScreen fantastico su tutte le API, comprese da API21 a API23

Prima di tutto leggi questo articolo e segui il BUON modo di creare una schermata iniziale.

Se il tuo logo è distorto o non si adatta e stai prendendo di mira solo API24 + puoi semplicemente ridimensionare il tuo vettore disegnabile direttamente nel suo file xml in questo modo:

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

nel codice sopra sto riscalando un disegnabile che ho disegnato su una tela 640x640 per essere 240x240. poi lo metto nella mia schermata iniziale disegnabile in questo modo e funziona alla grande:

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

il mio codice in realtà disegna solo il triangolo nell'immagine in basso, ma qui vedi cosa puoi ottenere con questo. La risoluzione è finalmente ottima rispetto ai bordi pixelati che stavo ottenendo quando usavo la bitmap. quindi usa un vettore disegnabile con tutti i mezzi (c'è un sito chiamato vectr che ho usato per creare il mio senza il fastidio di scaricare software specializzato).

MODIFICA per farlo funzionare anche su API21-22-23

Sebbene la soluzione di cui sopra funzioni per i dispositivi che eseguono API24 +, sono rimasto davvero deluso dopo aver installato la mia app su un dispositivo con API22. Ho notato che lo splashscreen stava di nuovo cercando di riempire l'intera visualizzazione e sembrava una merda. Dopo aver strappato le sopracciglia per mezza giornata ho finalmente forzato una soluzione bruta per pura forza di volontà.

devi creare un secondo file chiamato esattamente come lo splashscreen xml (diciamo splash_screen.xml) e posizionarlo in 2 cartelle chiamate drawable-v22 e drawable-v21 che creerai nella cartella res / (per vederle tu cambiare la visualizzazione del progetto da Android a Project). Questo serve per dire al tuo telefono di reindirizzare ai file collocati in quelle cartelle ogni volta che il dispositivo in questione esegue un'API corrispondente al suffisso -vXX nella cartella disegnabile, vedi questo link . inserire il codice seguente nell'elenco dei livelli del file splash_screen.xml creato in queste cartelle:

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

ecco come appaiono le cartelle

Per qualche ragione per queste API devi racchiudere il tuo disegnabile in una bitmap per farlo funzionare e fare in modo che il risultato finale sia lo stesso. Il problema è che devi utilizzare l'approccio con le cartelle disegnabili aggiuntive poiché la seconda versione del file splash_screen.xml farà sì che la schermata iniziale non venga visualizzata affatto sui dispositivi che eseguono API superiori a 23. Potrebbe anche essere necessario posizionare la prima versione di splash_screen.xml in drawable-v24 come impostazione predefinita di Android nella cartella drawable-vXX più vicina che può trovare per le risorse.

il mio splashscreen


4

Attualmente sto lavorando su una schermata iniziale con un disegno vettoriale centrato sia orizzontalmente che verticalmente. Ecco cosa ho ottenuto al livello 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>

Se vuoi regolare la dimensione del disegno vettoriale, modifica android:width eandroid:height attributi sopra, non necessariamente modificare il disegno originale.

Inoltre, la mia esperienza è NON inserire il disegno vettoriale in un tag bitmap, che non funziona mai per me. Il bitmap è per file in formato .png, .jpg e .gif, non per il disegno vettoriale.

Riferimento

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

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


1
Buona presa sui drawable vettoriali che devono essere all'interno di un tag <item> invece di un tag <bitmap>.
FrostRocket
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.